From b4171fe6209cf58cfba642f6aefdedeed9880095 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Wed, 24 Sep 2003 22:55:04 +0200 Subject: [PATCH 1/4] Fix for Bug #1392 "On Win, slave leaves one temp file after successf. replicating LOAD DATA INFILE" Windows-specific bug (we forgot to close a file before deleting it). Patch written by me, tested by Miguel (thanks!) and it works. --- sql/log.cc | 2 +- sql/log_event.cc | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/sql/log.cc b/sql/log.cc index bd5aeb02121..6307ac0c11e 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -870,7 +870,7 @@ void MYSQL_LOG::new_file(bool need_lock) close(LOG_CLOSE_TO_BE_OPENED); /* - Note that at this point, log_type == LOG_CLOSED (important for is_open()). + Note that at this point, log_type != LOG_CLOSED (important for is_open()). */ open(old_name, save_log_type, new_name_ptr, index_file_name, io_cache_type, diff --git a/sql/log_event.cc b/sql/log_event.cc index 82e9c5950a7..5c76bf3d055 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2382,6 +2382,16 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) } goto err; } + /* + We have an open file descriptor to the .info file; we need to close it + or Windows will refuse to delete the file in my_delete(). + */ + if (fd >= 0) + { + my_close(fd, MYF(0)); + end_io_cache(&file); + fd= -1; + } (void) my_delete(fname, MYF(MY_WME)); memcpy(p, ".data", 6); (void) my_delete(fname, MYF(MY_WME)); From 7826fce2649c7e44b9dd990b6dcdf377104494e4 Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Thu, 25 Sep 2003 01:25:19 +0400 Subject: [PATCH 2/4] Fixed BUG#1357 MySQL too eagerly cleanups temporary files for LOAD DATA (SQL_LOAD-...) --- sql/log_event.cc | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 82e9c5950a7..dbf433707a3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -140,11 +140,6 @@ Log_event::Log_event() /* Delete all temporary files used for SQL_LOAD. - - TODO - - When we get a 'server start' event, we should only remove - the files associated with the server id that just started. - Easily fixable by adding server_id as a prefix to the log files. */ static void cleanup_load_tmpdir() @@ -152,13 +147,30 @@ static void cleanup_load_tmpdir() MY_DIR *dirp; FILEINFO *file; uint i; + char fname[FN_REFLEN]; + char prefbuf[31]; + char *p; + if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME)))) return; - char fname[FN_REFLEN]; + + /* + When we are deleting temporary files, we should only remove + the files associated with the server id of our server. + We don't use event_server_id here because since we've disabled + direct binlogging of Create_file/Append_file/Exec_load events + we cannot meet Start_log event in the middle of events from one + LOAD DATA. + */ + p= strmake(prefbuf,"SQL_LOAD-",9); + p= int10_to_str(::server_id, p, 10); + *(p++)= '-'; + *p= 0; + for (i=0 ; i < (uint)dirp->number_off_files; i++) { file=dirp->dir_entry+i; - if (is_prefix(file->name,"SQL_LOAD-")) + if (is_prefix(file->name, prefbuf)) { fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME); my_delete(fname, MYF(0)); From 9854acae2538480fc1447a91762ca85e2dae922a Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Thu, 25 Sep 2003 00:14:46 +0200 Subject: [PATCH 3/4] Fix for BUG#1391: "If LOAD DATA INFILE 'small_file' fails on master, slave leaves temp files" (the bug is in the master) --- mysql-test/r/rpl_loaddata.result | 13 ++++++++- mysql-test/std_data/rpl_loaddata2.dat | 2 +- mysql-test/t/rpl_loaddata.test | 15 +++++++++++ sql/sql_load.cc | 39 ++++++++++++++++----------- 4 files changed, 52 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index 0302381c119..8b910d0d183 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -19,7 +19,7 @@ select * from t3; day id category name 2003-02-22 2461 b a a a @ %  ' " a 2003-03-22 2161 c asdf -2003-04-22 2416 a bbbbb +2003-03-22 2416 a bbbbb show master status; File Position Binlog_do_db Binlog_ignore_db slave-bin.001 964 @@ -55,3 +55,14 @@ reset slave; show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space 127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 +reset master; +create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), +unique(day)); +load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields +terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by +'\n##\n' starting by '>' ignore 1 lines; +Duplicate entry '2003-03-22' for key 1 +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.001 491 +drop table t2; diff --git a/mysql-test/std_data/rpl_loaddata2.dat b/mysql-test/std_data/rpl_loaddata2.dat index b883d9dcd58..04d84f1f45e 100644 --- a/mysql-test/std_data/rpl_loaddata2.dat +++ b/mysql-test/std_data/rpl_loaddata2.dat @@ -4,5 +4,5 @@ ## >2003-03-22,2161,%c%,%asdf% ## ->2003-04-22,2416,%a%,%bbbbb% +>2003-03-22,2416,%a%,%bbbbb% ## diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test index 4c4ff6a093e..a3bb8c9aec9 100644 --- a/mysql-test/t/rpl_loaddata.test +++ b/mysql-test/t/rpl_loaddata.test @@ -112,3 +112,18 @@ stop slave; reset slave; --replace_result $MASTER_MYPORT MASTER_PORT show slave status; + +# Finally, see if logging is done ok on master for a failing LOAD DATA INFILE + +connection master; +reset master; +create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), +unique(day)); +--error 1062; +load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields +terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by +'\n##\n' starting by '>' ignore 1 lines; +# To test that there is Create_file & Delete_file, we test if the binlog is as +# long as expected (can't do SHOW BINLOG EVENTS because of varying file_id). +show master status; +drop table t2; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 0ae6ccb4c4a..ca540a8cdc0 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -282,22 +282,31 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ha_autocommit_or_rollback(thd,error); if (!opt_old_rpl_compat && mysql_bin_log.is_open()) { + /* + Make sure last block (the one which caused the error) gets logged. + This is needed because otherwise after write of + (to the binlog, not to read_info (which is a cache)) + Delete_file_log_event the bad block will remain in read_info (because + pre_read is not called at the end of the last block; remember pre_read + is called whenever a new block is read from disk). + At the end of mysql_load(), the destructor of read_info will call + end_io_cache() which will flush read_info, so we will finally have + this in the binlog: + Append_block # The last successfull block + Delete_file + Append_block # The failing block + which is nonsense. + Or could also be (for a small file) + Create_file # The failing block + which is nonsense (Delete_file is not written in this case, because: + Create_file has not been written, so Delete_file is not written, then + when read_info is destroyed end_io_cache() is called which writes + Create_file. + */ + read_info.end_io_cache(); + /* If the file was not empty, wrote_create_file is true */ if (lf_info.wrote_create_file) { - /* - Make sure last block (the one which caused the error) gets logged. - This is needed because otherwise after write of - (to the binlog, not to read_info (which is a cache)) - Delete_file_log_event the bad block will remain in read_info. - At the end of mysql_load(), the destructor of read_info will call - end_io_cache() which will flush read_info, so we will finally have - this in the binlog: - Append_block # The last successfull block - Delete_file - Append_block # The failing block - which is nonsense. - */ - read_info.end_io_cache(); Delete_file_log_event d(thd, db, log_delayed); mysql_bin_log.write(&d); } @@ -327,7 +336,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } else { - read_info.end_io_cache(); // make sure last block gets logged + read_info.end_io_cache(); if (lf_info.wrote_create_file) { Execute_load_log_event e(thd, db, log_delayed); From e4c7496c141ad9990a42121bcdd53eb22e90df2f Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Thu, 25 Sep 2003 00:24:06 +0200 Subject: [PATCH 4/4] a small comment about why we call end_io_cache in mysql_load --- sql/sql_load.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/sql_load.cc b/sql/sql_load.cc index ca540a8cdc0..e692e7b8dab 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -336,6 +336,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } else { + /* + As already explained above, we need to call end_io_cache() or the last + block will be logged only after Execute_load_log_event (which is wrong), + when read_info is destroyed. + */ read_info.end_io_cache(); if (lf_info.wrote_create_file) {