Commit 6cf64b26 authored by unknown's avatar unknown

Bug #18199 PURGE BINARY LOGS fails silently with missing logs;

Bug #18453  Warning/error message if there is a mismatch between ...
 
There were three problems:
 
 1. the reported lack of warnings for the BEFORE syntax of PURGE;
 2. the similar lack of warnings for the TO syntax;
 3. incompatible behaviour between the two in that the latter blanked out
    regardlessly of presence or lack the actual file corresponding to
    an index record; the former version gave up at the first mismatch.

fixed with deploying the warning's generation and synronizing logics of 
purge_logs() and purge_logs_before_date().
my_stat() is called in either of two branches of purge_logs() (responsible
for the TO syntax of PURGE) similarly to how it has behaved in the BEFORE syntax.
If there is no actual binlog file, my_stat returns NULL and my_delete is
not invoked.
A critical error is reported to the user if a file from the index
could not be retrieved info about or deleted with a system error code
different than ENOENT.


sql/log.cc:
  generating warning in two functions.
  refining logics to call my_stat() by purge_logs() as it happens
  in purge_logs_before_date().
  my_delete() is called only if my_stat() ensured existance of the file.
  A critical error is reported to the user if a file from the index
  could not be my_stat():ed or my_delete():d with an error different
  than ENOENT.
sql/share/errmsg.txt:
  new error message
mysql-test/include/show_binary_logs.inc:
  a new macro - shortcut of show binary logs
mysql-test/r/binlog_index.result:
  new results
mysql-test/t/binlog_index.test:
  a regression test for the bugs
parent 1836625f
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_column 2 #
show binary logs;
flush logs;
flush logs;
flush logs;
show binary logs;
Log_name File_size
master-bin.000001 #
master-bin.000002 #
master-bin.000003 #
master-bin.000004 #
purge binary logs TO 'master-bin.000004';
Warnings:
Warning 1476 Being purged log MYSQLTEST_VARDIR/log/master-bin.000001 was not found
*** must show a list starting from the 'TO' argument of PURGE ***
show binary logs;
Log_name File_size
master-bin.000004 #
reset master;
flush logs;
flush logs;
flush logs;
*** must be a warning master-bin.000001 was not found ***
Warnings:
Warning 1476 Being purged log MYSQLTEST_VARDIR/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
master-bin.000004 #
reset master;
flush logs;
flush logs;
flush logs;
purge binary logs TO 'master-bin.000002';
ERROR HY000: Fatal error during log purge
show warnings;
Level Code Message
Error 1377 a problem with deleting MYSQLTEST_VARDIR/log/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;
End of tests
#
# testing of purging of binary log files bug#18199/Bug#18453
#
source include/have_log_bin.inc;
source include/not_embedded.inc;
#
# testing purge binary logs TO
#
flush logs;
flush logs;
flush logs;
source include/show_binary_logs.inc;
remove_file $MYSQLTEST_VARDIR/log/master-bin.000001;
# there must be a warning with file names
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
purge binary logs TO 'master-bin.000004';
--echo *** must show a list starting from the 'TO' argument of PURGE ***
source include/show_binary_logs.inc;
#
# testing purge binary logs BEFORE
#
reset master;
flush logs;
flush logs;
flush logs;
remove_file $MYSQLTEST_VARDIR/log/master-bin.000001;
--echo *** must be a warning master-bin.000001 was not found ***
let $date=`select NOW() + INTERVAL 1 MINUTE`;
--disable_query_log
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval purge binary logs BEFORE '$date';
--enable_query_log
--echo *** must show one record, of the active binlog, left in the index file after PURGE ***
source include/show_binary_logs.inc;
#
# testing a fatal error
# Turning a binlog file into a directory must be a portable setup
#
reset master;
flush logs;
flush logs;
flush logs;
remove_file $MYSQLTEST_VARDIR/log/master-bin.000001;
mkdir $MYSQLTEST_VARDIR/log/master-bin.000001;
--error ER_BINLOG_PURGE_FATAL_ERR
purge binary logs TO 'master-bin.000002';
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
show warnings;
rmdir $MYSQLTEST_VARDIR/log/master-bin.000001;
--disable_warnings
reset master;
--enable_warnings
--echo End of tests
...@@ -1180,6 +1180,8 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads) ...@@ -1180,6 +1180,8 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
RETURN VALUES RETURN VALUES
0 ok 0 ok
LOG_INFO_EOF to_log not found LOG_INFO_EOF to_log not found
LOG_INFO_FATAL if any other than ENOENT error from
my_stat() or my_delete()
*/ */
int MYSQL_LOG::purge_logs(const char *to_log, int MYSQL_LOG::purge_logs(const char *to_log,
...@@ -1207,30 +1209,72 @@ int MYSQL_LOG::purge_logs(const char *to_log, ...@@ -1207,30 +1209,72 @@ int MYSQL_LOG::purge_logs(const char *to_log,
goto err; goto err;
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) && while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
!log_in_use(log_info.log_file_name)) !log_in_use(log_info.log_file_name))
{
ulong file_size= 0;
if (decrease_log_space) //stat the file we want to delete
{ {
MY_STAT s; MY_STAT s;
if (!my_stat(log_info.log_file_name, &s, MYF(0)))
{
if (my_errno == ENOENT)
{
/* /*
If we could not stat, we can't know the amount It's not fatal if we can't stat a log file that does not exist;
of space that deletion will free. In most cases, If we could not stat, we won't delete.
deletion won't work either, so it's not a problem.
*/ */
if (my_stat(log_info.log_file_name,&s,MYF(0))) push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
file_size= s.st_size; ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
else log_info.log_file_name);
sql_print_information("Failed to execute my_stat on file '%s'", sql_print_information("Failed to execute my_stat on file '%s'",
log_info.log_file_name); log_info.log_file_name);
my_errno= 0;
} }
else
{
/* /*
It's not fatal if we can't delete a log file ; Other than ENOENT are fatal
if we could delete it, take its size into account
*/ */
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_BINLOG_PURGE_FATAL_ERR,
"a problem with getting info on being purged %s; "
"consider examining correspondence "
"of your binlog index file "
"to the actual binlog files",
log_info.log_file_name);
error= LOG_INFO_FATAL;
goto err;
}
}
else
{
DBUG_PRINT("info",("purging %s",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)) && decrease_log_space) if (!my_delete(log_info.log_file_name, MYF(0)))
*decrease_log_space-= file_size; {
if (decrease_log_space)
*decrease_log_space-= s.st_size;
}
else
{
if (my_errno == ENOENT)
{
push_warning_printf(current_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
{
push_warning_printf(current_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);
error= LOG_INFO_FATAL;
goto err;
}
}
}
if (find_next_log(&log_info, 0) || exit_loop) if (find_next_log(&log_info, 0) || exit_loop)
break; break;
} }
...@@ -1263,6 +1307,8 @@ int MYSQL_LOG::purge_logs(const char *to_log, ...@@ -1263,6 +1307,8 @@ int MYSQL_LOG::purge_logs(const char *to_log,
RETURN VALUES RETURN VALUES
0 ok 0 ok
LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
LOG_INFO_FATAL if any other than ENOENT error from
my_stat() or my_delete()
*/ */
int MYSQL_LOG::purge_logs_before_date(time_t purge_time) int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
...@@ -1286,11 +1332,66 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time) ...@@ -1286,11 +1332,66 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
while (strcmp(log_file_name, log_info.log_file_name) && while (strcmp(log_file_name, log_info.log_file_name) &&
!log_in_use(log_info.log_file_name)) !log_in_use(log_info.log_file_name))
{ {
/* It's not fatal even if we can't delete a log file */ if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)))
if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)) || {
stat_area.st_mtime >= purge_time) if (my_errno == ENOENT)
{
/*
It's not fatal if we can't stat a log file that does not exist.
*/
push_warning_printf(current_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
{
/*
Other than ENOENT are fatal
*/
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_BINLOG_PURGE_FATAL_ERR,
"a problem with getting info on being purged %s; "
"consider examining correspondence "
"of your binlog index file "
"to the actual binlog files",
log_info.log_file_name);
error= LOG_INFO_FATAL;
goto err;
}
}
else
{
if (stat_area.st_mtime >= purge_time)
break; break;
my_delete(log_info.log_file_name, MYF(0)); if (my_delete(log_info.log_file_name, MYF(0)))
{
if (my_errno == ENOENT)
{
/* It's not fatal even if we can't delete a log file */
push_warning_printf(current_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
{
push_warning_printf(current_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);
error= LOG_INFO_FATAL;
goto err;
}
}
}
if (find_next_log(&log_info, 0)) if (find_next_log(&log_info, 0))
break; break;
} }
......
...@@ -5641,3 +5641,5 @@ ER_NAME_BECOMES_EMPTY ...@@ -5641,3 +5641,5 @@ ER_NAME_BECOMES_EMPTY
eng "Name '%-.64s' has become ''" eng "Name '%-.64s' has become ''"
ER_AMBIGUOUS_FIELD_TERM ER_AMBIGUOUS_FIELD_TERM
eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY"
ER_LOG_PURGE_NO_FILE
eng "Being purged log %s was not found"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment