#At file:///home/acorreia/workspace.sun/repository.mysql/bzrwork/bug-45292/mysql-pe/ based on revid:gshchepa@stripped
3742 Alfranio Correia 2009-12-04 [merge]
merge mysql-5.1-bugteam --> mysql-pe
modified:
mysql-test/suite/binlog/r/binlog_index.result
mysql-test/suite/binlog/t/binlog_index.test
mysql-test/suite/rpl/r/rpl_bug41902.result
mysql-test/suite/rpl/t/rpl_bug41902.test
sql/log.cc
sql/log.h
sql/mysqld.cc
sql/rpl_rli.cc
=== modified file 'mysql-test/suite/binlog/r/binlog_index.result'
--- a/mysql-test/suite/binlog/r/binlog_index.result 2009-09-25 14:15:30 +0000
+++ b/mysql-test/suite/binlog/r/binlog_index.result 2009-12-04 15:16:06 +0000
@@ -1,3 +1,8 @@
+call mtr.add_suppression('Attempting backtrace');
+call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to process registered files that would be purged.');
+call mtr.add_suppression('MSYQL_BIN_LOG::open failed to sync the index file');
+call mtr.add_suppression('Turning logging off for the whole duration of the MySQL server process.');
+call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to clean registers before purging logs.');
flush logs;
flush logs;
flush logs;
@@ -21,7 +26,6 @@ flush logs;
*** must be a warning master-bin.000001 was not found ***
Warnings:
Warning 1612 Being purged log master-bin.000001 was not found
-Warning 1612 Being purged log master-bin.000001 was not found
*** must show one record, of the active binlog, left in the index file after PURGE ***
show binary logs;
Log_name File_size
@@ -31,10 +35,117 @@ flush logs;
flush logs;
flush logs;
purge binary logs TO 'master-bin.000002';
-ERROR HY000: Fatal error during log purge
+ERROR HY000: a problem with deleting ./master-bin.000001; consider examining correspondence of your binlog index file to the actual binlog files
show warnings;
Level Code Message
-Warning 1377 a problem with deleting master-bin.000001; consider examining correspondence of your binlog index file to the actual binlog files
+Error 1377 a problem with deleting master-bin.000001; consider examining correspondence of your binlog index file to the actual binlog files
Error 1377 Fatal error during log purge
reset master;
+# crash_purge_before_update_index
+flush logs;
+SET SESSION debug="+d,crash_purge_before_update_index";
+purge binary logs TO 'master-bin.000002';
+ERROR HY000: Lost connection to MySQL server during query
+SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
+SELECT @index;
+@index
+master-bin.000001
+master-bin.000002
+master-bin.000003
+
+# crash_purge_non_critical_after_update_index
+flush logs;
+SET SESSION debug="+d,crash_purge_non_critical_after_update_index";
+purge binary logs TO 'master-bin.000004';
+ERROR HY000: Lost connection to MySQL server during query
+SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
+SELECT @index;
+@index
+master-bin.000004
+master-bin.000005
+
+# crash_purge_critical_after_update_index
+flush logs;
+SET SESSION debug="+d,crash_purge_critical_after_update_index";
+purge binary logs TO 'master-bin.000006';
+ERROR HY000: Lost connection to MySQL server during query
+SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
+SELECT @index;
+@index
+master-bin.000006
+master-bin.000007
+
+# crash_create_non_critical_before_update_index
+SET SESSION debug="+d,crash_create_non_critical_before_update_index";
+flush logs;
+ERROR HY000: Lost connection to MySQL server during query
+SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
+SELECT @index;
+@index
+master-bin.000006
+master-bin.000007
+master-bin.000008
+
+# crash_create_critical_before_update_index
+SET SESSION debug="+d,crash_create_critical_before_update_index";
+flush logs;
+ERROR HY000: Lost connection to MySQL server during query
+SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
+SELECT @index;
+@index
+master-bin.000006
+master-bin.000007
+master-bin.000008
+master-bin.000009
+
+# crash_create_after_update_index
+SET SESSION debug="+d,crash_create_after_update_index";
+flush logs;
+ERROR HY000: Lost connection to MySQL server during query
+SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
+SELECT @index;
+@index
+master-bin.000006
+master-bin.000007
+master-bin.000008
+master-bin.000009
+master-bin.000010
+master-bin.000011
+
+#
+# This should put the server in unsafe state and stop
+# accepting any command. If we inject a fault at this
+# point and continue the execution the server crashes.
+# Besides the flush command does not report an error.
+#
+# fault_injection_registering_index
+SET SESSION debug="+d,fault_injection_registering_index";
+flush logs;
+SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
+SELECT @index;
+@index
+master-bin.000006
+master-bin.000007
+master-bin.000008
+master-bin.000009
+master-bin.000010
+master-bin.000011
+master-bin.000012
+
+# fault_injection_updating_index
+SET SESSION debug="+d,fault_injection_updating_index";
+flush logs;
+SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
+SELECT @index;
+@index
+master-bin.000006
+master-bin.000007
+master-bin.000008
+master-bin.000009
+master-bin.000010
+master-bin.000011
+master-bin.000012
+master-bin.000013
+
+SET SESSION debug="";
End of tests
=== modified file 'mysql-test/suite/binlog/t/binlog_index.test'
--- a/mysql-test/suite/binlog/t/binlog_index.test 2008-04-05 11:09:53 +0000
+++ b/mysql-test/suite/binlog/t/binlog_index.test 2009-12-04 14:40:42 +0000
@@ -3,6 +3,15 @@
#
source include/have_log_bin.inc;
source include/not_embedded.inc;
+call mtr.add_suppression('Attempting backtrace');
+call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to process registered files that would be purged.');
+call mtr.add_suppression('MSYQL_BIN_LOG::open failed to sync the index file');
+call mtr.add_suppression('Turning logging off for the whole duration of the MySQL server process.');
+call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to clean registers before purging logs.');
+let $old=`select @@debug`;
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $INDEX=$MYSQLD_DATADIR/master-bin.index;
#
# testing purge binary logs TO
@@ -13,7 +22,6 @@ flush logs;
flush logs;
source include/show_binary_logs.inc;
-let $MYSQLD_DATADIR= `select @@datadir`;
remove_file $MYSQLD_DATADIR/master-bin.000001;
# there must be a warning with file names
@@ -66,4 +74,159 @@ rmdir $MYSQLD_DATADIR/master-bin.000001;
--disable_warnings
reset master;
--enable_warnings
+
+--echo # crash_purge_before_update_index
+flush logs;
+
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+SET SESSION debug="+d,crash_purge_before_update_index";
+--error 2013
+purge binary logs TO 'master-bin.000002';
+
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+file_exists $MYSQLD_DATADIR/master-bin.000001;
+file_exists $MYSQLD_DATADIR/master-bin.000002;
+file_exists $MYSQLD_DATADIR/master-bin.000003;
+--chmod 0644 $INDEX
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval SET @index=LOAD_FILE('$index')
+-- replace_regex /\.[\\\/]master/master/
+SELECT @index;
+
+--echo # crash_purge_non_critical_after_update_index
+flush logs;
+
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+SET SESSION debug="+d,crash_purge_non_critical_after_update_index";
+--error 2013
+purge binary logs TO 'master-bin.000004';
+
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--error 1
+file_exists $MYSQLD_DATADIR/master-bin.000001;
+--error 1
+file_exists $MYSQLD_DATADIR/master-bin.000002;
+--error 1
+file_exists $MYSQLD_DATADIR/master-bin.000003;
+--chmod 0644 $INDEX
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval SET @index=LOAD_FILE('$index')
+-- replace_regex /\.[\\\/]master/master/
+SELECT @index;
+
+--echo # crash_purge_critical_after_update_index
+flush logs;
+
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+SET SESSION debug="+d,crash_purge_critical_after_update_index";
+--error 2013
+purge binary logs TO 'master-bin.000006';
+
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--error 1
+file_exists $MYSQLD_DATADIR/master-bin.000004;
+--error 1
+file_exists $MYSQLD_DATADIR/master-bin.000005;
+file_exists $MYSQLD_DATADIR/master-bin.000006;
+file_exists $MYSQLD_DATADIR/master-bin.000007;
+--error 1
+file_exists $MYSQLD_DATADIR/master-bin.000008;
+--chmod 0644 $INDEX
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval SET @index=LOAD_FILE('$index')
+-- replace_regex /\.[\\\/]master/master/
+SELECT @index;
+
+--echo # crash_create_non_critical_before_update_index
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+SET SESSION debug="+d,crash_create_non_critical_before_update_index";
+--error 2013
+flush logs;
+
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+file_exists $MYSQLD_DATADIR/master-bin.000008;
+--error 1
+file_exists $MYSQLD_DATADIR/master-bin.000009;
+--chmod 0644 $INDEX
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval SET @index=LOAD_FILE('$index')
+-- replace_regex /\.[\\\/]master/master/
+SELECT @index;
+
+--echo # crash_create_critical_before_update_index
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+SET SESSION debug="+d,crash_create_critical_before_update_index";
+--error 2013
+flush logs;
+
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+file_exists $MYSQLD_DATADIR/master-bin.000009;
+--error 1
+file_exists $MYSQLD_DATADIR/master-bin.000010;
+--error 1
+file_exists $MYSQLD_DATADIR/master-bin.000011;
+--chmod 0644 $INDEX
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval SET @index=LOAD_FILE('$index')
+-- replace_regex /\.[\\\/]master/master/
+SELECT @index;
+
+--echo # crash_create_after_update_index
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+SET SESSION debug="+d,crash_create_after_update_index";
+--error 2013
+flush logs;
+
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+file_exists $MYSQLD_DATADIR/master-bin.000010;
+file_exists $MYSQLD_DATADIR/master-bin.000011;
+--chmod 0644 $INDEX
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval SET @index=LOAD_FILE('$index')
+-- replace_regex /\.[\\\/]master/master/
+SELECT @index;
+
+--echo #
+--echo # This should put the server in unsafe state and stop
+--echo # accepting any command. If we inject a fault at this
+--echo # point and continue the execution the server crashes.
+--echo # Besides the flush command does not report an error.
+--echo #
+
+--echo # fault_injection_registering_index
+SET SESSION debug="+d,fault_injection_registering_index";
+flush logs;
+--source include/restart_mysqld.inc
+
+--chmod 0644 $INDEX
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval SET @index=LOAD_FILE('$index')
+-- replace_regex /\.[\\\/]master/master/
+SELECT @index;
+
+--echo # fault_injection_updating_index
+SET SESSION debug="+d,fault_injection_updating_index";
+flush logs;
+--source include/restart_mysqld.inc
+
+--chmod 0644 $INDEX
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval SET @index=LOAD_FILE('$index')
+-- replace_regex /\.[\\\/]master/master/
+SELECT @index;
+
+eval SET SESSION debug="$old";
+
--echo End of tests
=== modified file 'mysql-test/suite/rpl/r/rpl_bug41902.result'
--- a/mysql-test/suite/rpl/r/rpl_bug41902.result 2009-09-01 12:31:10 +0000
+++ b/mysql-test/suite/rpl/r/rpl_bug41902.result 2009-12-04 15:16:06 +0000
@@ -4,6 +4,7 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
+call mtr.add_suppression('MYSQL_BIN_LOG::purge_logs was called with file ./master-bin.000001 not listed in the index.');
stop slave;
SET @@debug="d,simulate_find_log_pos_error";
reset slave;
=== modified file 'mysql-test/suite/rpl/t/rpl_bug41902.test'
--- a/mysql-test/suite/rpl/t/rpl_bug41902.test 2009-09-01 12:31:10 +0000
+++ b/mysql-test/suite/rpl/t/rpl_bug41902.test 2009-12-04 15:16:06 +0000
@@ -4,6 +4,8 @@
source include/have_debug.inc;
source include/master-slave.inc;
+call mtr.add_suppression('MYSQL_BIN_LOG::purge_logs was called with file ./master-bin.000001 not listed in the index.');
+
#
# test checks that
@@ -17,7 +19,6 @@ connection slave;
stop slave;
SET @@debug="d,simulate_find_log_pos_error";
-
--error ER_UNKNOWN_TARGET_BINLOG
reset slave;
show warnings;
=== modified file 'sql/log.cc'
--- a/sql/log.cc 2009-11-27 14:56:49 +0000
+++ b/sql/log.cc 2009-12-04 15:16:06 +0000
@@ -3193,6 +3193,22 @@ void MYSQL_LOG::init(enum_log_type log_t
}
+bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
+ const char *new_name,
+ enum_log_type log_type_arg,
+ enum cache_type io_cache_type_arg)
+{
+ init(log_type_arg, io_cache_type_arg);
+
+ if (new_name && !strmov(log_file_name, new_name))
+ return TRUE;
+ else if (!new_name && generate_new_name(log_file_name, log_name))
+ return TRUE;
+
+ return FALSE;
+}
+
+
/*
Open a (new) log file.
@@ -3225,17 +3241,14 @@ bool MYSQL_LOG::open(const char *log_nam
write_error= 0;
- init(log_type_arg, io_cache_type_arg);
-
if (!(name= my_strdup(log_name, MYF(MY_WME))))
{
name= (char *)log_name; // for the error message
goto err;
}
- if (new_name)
- strmov(log_file_name, new_name);
- else if (generate_new_name(log_file_name, name))
+ if (init_and_set_log_file_name(name, new_name,
+ log_type_arg, io_cache_type_arg))
goto err;
if (io_cache_type == SEQ_READ_APPEND)
@@ -4322,7 +4335,7 @@ MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_
*/
index_file_name[0] = 0;
bzero((char*) &index_file, sizeof(index_file));
- bzero((char*) &purge_temp, sizeof(purge_temp));
+ bzero((char*) &purge_index_file, sizeof(purge_index_file));
}
/* this is called only once */
@@ -4371,7 +4384,7 @@ void MYSQL_BIN_LOG::init_pthread_objects
bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
- const char *log_name)
+ const char *log_name, bool need_mutex)
{
File index_file_nr= -1;
DBUG_ASSERT(!my_b_inited(&index_file));
@@ -4396,7 +4409,8 @@ bool MYSQL_BIN_LOG::open_index_file(cons
init_io_cache(&index_file, index_file_nr,
IO_SIZE, WRITE_CACHE,
my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
- 0, MYF(MY_WME | MY_WAIT_IF_FULL)))
+ 0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
+ DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
{
/*
TODO: all operations creating/deleting the index file or a log, should
@@ -4407,6 +4421,28 @@ bool MYSQL_BIN_LOG::open_index_file(cons
my_close(index_file_nr,MYF(0));
return TRUE;
}
+
+#ifdef HAVE_REPLICATION
+ /*
+ Sync the index by purging any binary log file that is not registered.
+ In other words, either purge binary log files that were removed from
+ the index but not purged from the file system due to a crash or purge
+ any binary log file that was created but not register in the index
+ due to a crash.
+ */
+
+ if (set_purge_index_file_name(index_file_name_arg) ||
+ open_purge_index_file(FALSE) ||
+ purge_index_entry(NULL, NULL, need_mutex) ||
+ close_purge_index_file() ||
+ DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0))
+ {
+ sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index "
+ "file.");
+ return TRUE;
+ }
+#endif
+
return FALSE;
}
@@ -4431,17 +4467,44 @@ bool MYSQL_BIN_LOG::open(const char *log
enum cache_type io_cache_type_arg,
bool no_auto_events_arg,
ulong max_size_arg,
- bool null_created_arg)
+ bool null_created_arg,
+ bool need_mutex)
{
File file= -1;
+
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
- write_error=0;
+ if (init_and_set_log_file_name(log_name, new_name, log_type_arg,
+ io_cache_type_arg))
+ {
+ sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name.");
+ DBUG_RETURN(1);
+ }
+
+#ifdef HAVE_REPLICATION
+ if (open_purge_index_file(TRUE) ||
+ register_create_index_entry(log_file_name) ||
+ sync_purge_index_file() ||
+ DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0))
+ {
+ sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
+ DBUG_RETURN(1);
+ }
+ DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", abort(););
+#endif
+
+ write_error= 0;
/* open the main log file */
- if (MYSQL_LOG::open(log_name, log_type_arg, new_name, io_cache_type_arg))
+ if (MYSQL_LOG::open(log_name, log_type_arg, new_name,
+ io_cache_type_arg))
+ {
+#ifdef HAVE_REPLICATION
+ close_purge_index_file();
+#endif
DBUG_RETURN(1); /* all warnings issued */
+ }
init(no_auto_events_arg, max_size_arg);
@@ -4467,9 +4530,6 @@ bool MYSQL_BIN_LOG::open(const char *log
write_file_name_to_index_file= 1;
}
- DBUG_ASSERT(my_b_inited(&index_file) != 0);
- reinit_io_cache(&index_file, WRITE_CACHE,
- my_b_filelength(&index_file), 0, 0);
if (need_start_event && !no_auto_events)
{
/*
@@ -4527,23 +4587,44 @@ bool MYSQL_BIN_LOG::open(const char *log
if (write_file_name_to_index_file)
{
+#ifdef HAVE_REPLICATION
+ DBUG_EXECUTE_IF("crash_create_critical_before_update_index", abort(););
+#endif
+
+ DBUG_ASSERT(my_b_inited(&index_file) != 0);
+ reinit_io_cache(&index_file, WRITE_CACHE,
+ my_b_filelength(&index_file), 0, 0);
/*
As this is a new log file, we write the file name to the index
file. As every time we write to the index file, we sync it.
*/
- if (my_b_write(&index_file, (uchar*) log_file_name,
- strlen(log_file_name)) ||
- my_b_write(&index_file, (uchar*) "\n", 1) ||
- flush_io_cache(&index_file) ||
+ if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
+ my_b_write(&index_file, (uchar*) log_file_name,
+ strlen(log_file_name)) ||
+ my_b_write(&index_file, (uchar*) "\n", 1) ||
+ flush_io_cache(&index_file) ||
my_sync(index_file.file, MYF(MY_WME)))
- goto err;
+ goto err;
+
+#ifdef HAVE_REPLICATION
+ DBUG_EXECUTE_IF("crash_create_after_update_index", abort(););
+#endif
}
}
log_state= LOG_OPENED;
+#ifdef HAVE_REPLICATION
+ close_purge_index_file();
+#endif
+
DBUG_RETURN(0);
err:
+#ifdef HAVE_REPLICATION
+ if (is_inited_purge_index_file())
+ purge_index_entry(NULL, NULL, need_mutex);
+ close_purge_index_file();
+#endif
sql_print_error("Could not use %s for logging (error %d). \
Turning logging off for the whole duration of the MySQL server process. \
To turn it on again: fix the cause, \
@@ -4807,8 +4888,15 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
name=0; // Protect against free
close(LOG_CLOSE_TO_BE_OPENED);
- /* First delete all old log files */
+ /*
+ First delete all old log files and then update the index file.
+ As we first delete the log files and do not use sort of logging,
+ a crash may lead to an inconsistent state where the index has
+ references to non-existent files.
+ We need to invert the steps and use the purge_index_file methods
+ in order to make the operation safe.
+ */
if ((err= find_log_pos(&linfo, NullS, 0)) != 0)
{
uint errcode= purge_log_get_error_code(err);
@@ -4878,8 +4966,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
}
if (!thd->slave_thread)
need_start_event=1;
- if (!open_index_file(index_file_name, 0))
- open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0);
+ if (!open_index_file(index_file_name, 0, FALSE))
+ open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE);
my_free((uchar*) save_name, MYF(0));
err:
@@ -5068,7 +5156,7 @@ int MYSQL_BIN_LOG::purge_logs(const char
bool need_update_threads,
ulonglong *decrease_log_space)
{
- int error;
+ int error= 0;
bool exit_loop= 0;
LOG_INFO log_info;
THD *thd= current_thd;
@@ -5079,33 +5167,15 @@ int MYSQL_BIN_LOG::purge_logs(const char
pthread_mutex_lock(&LOCK_index);
if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
{
- sql_print_error("MYSQL_LOG::purge_logs was called with file %s not "
+ sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not "
"listed in the index.", to_log);
goto err;
}
- /*
- For crash recovery reasons the index needs to be updated before
- any files are deleted. Move files to be deleted into a temp file
- to be processed after the index is updated.
- */
- if (!my_b_inited(&purge_temp))
- {
- if ((error=open_cached_file(&purge_temp, mysql_tmpdir, TEMP_PREFIX,
- DISK_BUFFER_SIZE, MYF(MY_WME))))
- {
- sql_print_error("MYSQL_LOG::purge_logs failed to open purge_temp");
- goto err;
- }
- }
- else
+ if ((error= open_purge_index_file(TRUE)))
{
- if ((error=reinit_io_cache(&purge_temp, WRITE_CACHE, 0, 0, 1)))
- {
- sql_print_error("MYSQL_LOG::purge_logs failed to reinit purge_temp "
- "for write");
- goto err;
- }
+ sql_print_error("MYSQL_BIN_LOG::purge_logs failed to sync the index file.");
+ goto err;
}
/*
@@ -5115,51 +5185,181 @@ int MYSQL_BIN_LOG::purge_logs(const char
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
goto err;
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
+ !is_active(log_info.log_file_name) &&
!log_in_use(log_info.log_file_name))
{
- if ((error=my_b_write(&purge_temp, (const uchar*)log_info.log_file_name,
- strlen(log_info.log_file_name))) ||
- (error=my_b_write(&purge_temp, (const uchar*)"\n", 1)))
+ if ((error= register_purge_index_entry(log_info.log_file_name)))
{
- sql_print_error("MYSQL_LOG::purge_logs failed to copy %s to purge_temp",
+ sql_print_error("MYSQL_BIN_LOG::purge_logs failed to copy %s to register file.",
log_info.log_file_name);
goto err;
}
if (find_next_log(&log_info, 0) || exit_loop)
- break;
- }
+ break;
+ }
+
+ DBUG_EXECUTE_IF("crash_purge_before_update_index", abort(););
+
+ if ((error= sync_purge_index_file()))
+ {
+ sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file.");
+ goto err;
+ }
/* We know how many files to delete. Update index file. */
if ((error=update_log_index(&log_info, need_update_threads)))
{
- sql_print_error("MSYQL_LOG::purge_logs failed to update the index file");
+ sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file");
goto err;
}
- DBUG_EXECUTE_IF("crash_after_update_index", DBUG_ABORT(););
+ DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", abort(););
+
+err:
+ /* Read each entry from purge_index_file and delete the file. */
+ if (is_inited_purge_index_file() &&
+ (error= purge_index_entry(thd, decrease_log_space, FALSE)))
+ sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
+ " that would be purged.");
+ close_purge_index_file();
+
+ DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", abort(););
+
+ if (need_mutex)
+ pthread_mutex_unlock(&LOCK_index);
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name)
+{
+ int error= 0;
+ DBUG_ENTER("MYSQL_BIN_LOG::set_purge_index_file_name");
+ if (fn_format(purge_index_file_name, base_file_name, mysql_data_home,
+ ".~rec~", MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH |
+ MY_REPLACE_EXT)) == NULL)
+ {
+ error= 1;
+ sql_print_error("MYSQL_BIN_LOG::set_purge_index_file_name failed to set "
+ "file name.");
+ }
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::open_purge_index_file(bool destroy)
+{
+ int error= 0;
+ File file= -1;
+
+ DBUG_ENTER("MYSQL_BIN_LOG::open_purge_index_file");
+
+ if (destroy)
+ close_purge_index_file();
+
+ if (!my_b_inited(&purge_index_file))
+ {
+ if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY,
+ MYF(MY_WME | ME_WAITTANG))) < 0 ||
+ init_io_cache(&purge_index_file, file, IO_SIZE,
+ (destroy ? WRITE_CACHE : READ_CACHE),
+ 0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ error= 1;
+ sql_print_error("MYSQL_BIN_LOG::open_purge_index_file failed to open register "
+ " file.");
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::close_purge_index_file()
+{
+ int error= 0;
+
+ DBUG_ENTER("MYSQL_BIN_LOG::close_purge_index_file");
+
+ if (my_b_inited(&purge_index_file))
+ {
+ end_io_cache(&purge_index_file);
+ error= my_close(purge_index_file.file, MYF(0));
+ }
+ my_delete(purge_index_file_name, MYF(0));
+ bzero((char*) &purge_index_file, sizeof(purge_index_file));
+
+ DBUG_RETURN(error);
+}
+
+bool MYSQL_BIN_LOG::is_inited_purge_index_file()
+{
+ DBUG_ENTER("MYSQL_BIN_LOG::is_inited_purge_index_file");
+ DBUG_RETURN (my_b_inited(&purge_index_file));
+}
+
+int MYSQL_BIN_LOG::sync_purge_index_file()
+{
+ int error= 0;
+ DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file");
+
+ if ((error= flush_io_cache(&purge_index_file)) ||
+ (error= my_sync(purge_index_file.file, MYF(MY_WME))))
+ DBUG_RETURN(error);
+
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry)
+{
+ int error= 0;
+ DBUG_ENTER("MYSQL_BIN_LOG::register_purge_index_entry");
+
+ if ((error=my_b_write(&purge_index_file, (const uchar*)entry, strlen(entry))) ||
+ (error=my_b_write(&purge_index_file, (const uchar*)"\n", 1)))
+ DBUG_RETURN (error);
+
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::register_create_index_entry(const char *entry)
+{
+ DBUG_ENTER("MYSQL_BIN_LOG::register_create_index_entry");
+ DBUG_RETURN(register_purge_index_entry(entry));
+}
+
+int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
+ bool need_mutex)
+{
+ MY_STAT s;
+ int error= 0;
+ LOG_INFO log_info;
+ LOG_INFO check_log_info;
+
+ DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
+
+ /*
+ The index file must be initialized before we proceed with the purge
+ operation.
+ */
+ DBUG_ASSERT(my_b_inited(&purge_index_file));
- /* Switch purge_temp for read. */
- if ((error=reinit_io_cache(&purge_temp, READ_CACHE, 0, 0, 0)))
+ if ((error= reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0)))
{
- sql_print_error("MSYQL_LOG::purge_logs failed to reinit purge_temp "
- "for read");
+ sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register "
+ "file for read");
goto err;
}
- /* Read each entry from purge_temp and delete the file. */
for (;;)
{
uint length;
- if ((length=my_b_gets(&purge_temp, log_info.log_file_name,
+ if ((length=my_b_gets(&purge_index_file, log_info.log_file_name,
FN_REFLEN)) <= 1)
{
- if (purge_temp.error)
+ if (purge_index_file.error)
{
- error= purge_temp.error;
- sql_print_error("MSYQL_LOG::purge_logs error %d reading from "
- "purge_temp", error);
+ error= purge_index_file.error;
+ sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from "
+ "register file.", error);
goto err;
}
@@ -5170,9 +5370,6 @@ int MYSQL_BIN_LOG::purge_logs(const char
/* Get rid of the trailing '\n' */
log_info.log_file_name[length-1]= 0;
- ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
-
- MY_STAT s;
if (!my_stat(log_info.log_file_name, &s, MYF(0)))
{
if (my_errno == ENOENT)
@@ -5220,67 +5417,96 @@ int MYSQL_BIN_LOG::purge_logs(const char
}
else
{
- DBUG_PRINT("info",("purging %s",log_info.log_file_name));
- if (!my_delete(log_info.log_file_name, MYF(0)))
+ if ((error= find_log_pos(&check_log_info, log_info.log_file_name, need_mutex)))
{
- if (decrease_log_space)
- *decrease_log_space-= s.st_size;
- }
- else
- {
- if (my_errno == ENOENT)
+ if (error != LOG_INFO_EOF)
{
if (thd)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_BINLOG_PURGE_FATAL_ERR,
+ "a problem with deleting %s and "
+ "reading the binlog index file",
log_info.log_file_name);
}
- sql_print_information("Failed to delete file '%s'",
- log_info.log_file_name);
- my_errno= 0;
+ else
+ {
+ sql_print_information("Failed to delete file '%s' and "
+ "read the binlog index file",
+ log_info.log_file_name);
+ }
+ goto err;
+ }
+
+ error= 0;
+ if (!need_mutex)
+ {
+ /*
+ This is to avoid triggering an error in NDB.
+ */
+ ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
+ }
+
+ DBUG_PRINT("info",("purging %s",log_info.log_file_name));
+ if (!my_delete(log_info.log_file_name, MYF(0)))
+ {
+ if (decrease_log_space)
+ *decrease_log_space-= s.st_size;
}
else
{
- if (thd)
+ if (my_errno == ENOENT)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_BINLOG_PURGE_FATAL_ERR,
- "a problem with deleting %s; "
- "consider examining correspondence "
- "of your binlog index file "
- "to the actual binlog files",
- log_info.log_file_name);
+ if (thd)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+ log_info.log_file_name);
+ }
+ sql_print_information("Failed to delete file '%s'",
+ log_info.log_file_name);
+ my_errno= 0;
}
else
{
- sql_print_information("Failed to delete file '%s'; "
+ if (thd)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_BINLOG_PURGE_FATAL_ERR,
+ "a problem with deleting %s; "
"consider examining correspondence "
"of your binlog index file "
"to the actual binlog files",
log_info.log_file_name);
- }
- if (my_errno == EMFILE)
- {
- DBUG_PRINT("info",
- ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
- error= LOG_INFO_EMFILE;
+ }
+ else
+ {
+ sql_print_information("Failed to delete file '%s'; "
+ "consider examining correspondence "
+ "of your binlog index file "
+ "to the actual binlog files",
+ log_info.log_file_name);
+ }
+ if (my_errno == EMFILE)
+ {
+ DBUG_PRINT("info",
+ ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
+ error= LOG_INFO_EMFILE;
+ goto err;
+ }
+ error= LOG_INFO_FATAL;
goto err;
}
- error= LOG_INFO_FATAL;
- goto err;
}
}
}
}
err:
- close_cached_file(&purge_temp);
- if (need_mutex)
- pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
+
/**
Remove all logs before the given file date from disk and from the
index file.
@@ -5317,7 +5543,8 @@ int MYSQL_BIN_LOG::purge_logs_before_dat
goto err;
while (strcmp(log_file_name, log_info.log_file_name) &&
- !log_in_use(log_info.log_file_name))
+ !is_active(log_info.log_file_name) &&
+ !log_in_use(log_info.log_file_name))
{
if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)))
{
@@ -5326,14 +5553,6 @@ int MYSQL_BIN_LOG::purge_logs_before_dat
/*
It's not fatal if we can't stat a log file that does not exist.
*/
- if (thd)
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
- log_info.log_file_name);
- }
- sql_print_information("Failed to execute my_stat on file '%s'",
- log_info.log_file_name);
my_errno= 0;
}
else
@@ -5528,9 +5747,9 @@ void MYSQL_BIN_LOG::new_file_impl(bool n
*/
/* reopen index binlog file, BUG#34582 */
- if (!open_index_file(index_file_name, 0))
- open(old_name, log_type, new_name_ptr,
- io_cache_type, no_auto_events, max_size, 1);
+ if (!open_index_file(index_file_name, 0, FALSE))
+ open(old_name, log_type, new_name_ptr,
+ io_cache_type, no_auto_events, max_size, 1, FALSE);
my_free(old_name,MYF(0));
end:
@@ -7493,7 +7712,7 @@ int TC_LOG_BINLOG::open(const char *opt_
if (using_heuristic_recover())
{
/* generate a new binlog to mask a corrupted one */
- open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0);
+ open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0, TRUE);
cleanup();
return 1;
}
=== modified file 'sql/log.h'
--- a/sql/log.h 2009-10-26 14:02:26 +0000
+++ b/sql/log.h 2009-12-04 15:16:06 +0000
@@ -226,6 +226,10 @@ public:
enum_log_type log_type,
const char *new_name,
enum cache_type io_cache_type_arg);
+ bool init_and_set_log_file_name(const char *log_name,
+ const char *new_name,
+ enum_log_type log_type_arg,
+ enum cache_type io_cache_type_arg);
void init(enum_log_type log_type_arg,
enum cache_type io_cache_type_arg);
void close(uint exiting);
@@ -347,14 +351,15 @@ class MYSQL_BIN_LOG: public TC_LOG, priv
pthread_cond_t update_cond;
ulonglong bytes_written;
IO_CACHE index_file;
+ char index_file_name[FN_REFLEN];
/*
- purge_temp is a temp file used in purge_logs so that the index file
+ purge_file is a temp file used in purge_logs so that the index file
can be updated before deleting files from disk, yielding better crash
recovery. It is created on demand the first time purge_logs is called
and then reused for subsequent calls. It is cleaned up in cleanup().
*/
- IO_CACHE purge_temp;
- char index_file_name[FN_REFLEN];
+ IO_CACHE purge_index_file;
+ char purge_index_file_name[FN_REFLEN];
/*
The max size before rotation (usable only if log_type == LOG_BIN: binary
logs and relay logs).
@@ -476,9 +481,10 @@ public:
const char *new_name,
enum cache_type io_cache_type_arg,
bool no_auto_events_arg, ulong max_size,
- bool null_created);
+ bool null_created,
+ bool need_mutex);
bool open_index_file(const char *index_file_name_arg,
- const char *log_name);
+ const char *log_name, bool need_mutex);
/* Use this to start writing a new log file */
void new_file();
@@ -525,6 +531,16 @@ public:
ulonglong *decrease_log_space);
int purge_logs_before_date(time_t purge_time);
int purge_first_log(Relay_log_info* rli, bool included);
+ int set_purge_index_file_name(const char *base_file_name);
+ int open_purge_index_file(bool destroy);
+ bool is_inited_purge_index_file();
+ int close_purge_index_file();
+ int clean_purge_index_file();
+ int sync_purge_index_file();
+ int register_purge_index_entry(const char* entry);
+ int register_create_index_entry(const char* entry);
+ int purge_index_entry(THD *thd, ulonglong *decrease_log_space,
+ bool need_mutex);
bool reset_logs(THD* thd);
void close(uint exiting);
=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc 2009-11-27 14:56:49 +0000
+++ b/sql/mysqld.cc 2009-12-04 15:16:06 +0000
@@ -4244,7 +4244,7 @@ a file name for --log-bin-index option",
my_free(opt_bin_logname, MYF(MY_ALLOW_ZERO_PTR));
opt_bin_logname=my_strdup(buf, MYF(0));
}
- if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln))
+ if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln, TRUE))
{
unireg_abort(1);
}
@@ -4451,7 +4451,7 @@ a file name for --log-bin-index option",
}
if (opt_bin_log && mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0,
- WRITE_CACHE, 0, max_binlog_size, 0))
+ WRITE_CACHE, 0, max_binlog_size, 0, TRUE))
unireg_abort(1);
#ifdef HAVE_REPLICATION
=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc 2009-11-28 05:23:28 +0000
+++ b/sql/rpl_rli.cc 2009-12-04 15:16:06 +0000
@@ -1066,10 +1066,10 @@ a file name for --relay-log-index option
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
*/
- if (relay_log.open_index_file(opt_relaylog_index_name, ln) ||
+ if (relay_log.open_index_file(opt_relaylog_index_name, ln, TRUE) ||
relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0,
(max_relay_log_size ? max_relay_log_size :
- max_binlog_size), 1))
+ max_binlog_size), 1, TRUE))
{
sql_print_error("Failed in open_log() called from Relay_log_info::init_info()");
DBUG_RETURN(1);
Attachment: [text/bzr-bundle]
| Thread |
|---|
| • bzr commit into mysql-pe branch (alfranio.correia:3742) | Alfranio Correia | 4 Dec |