mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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.
This commit is contained in:
3
mysql-test/include/show_binary_logs.inc
Normal file
3
mysql-test/include/show_binary_logs.inc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
|
||||||
|
--replace_column 2 #
|
||||||
|
show binary logs;
|
39
mysql-test/r/binlog_index.result
Normal file
39
mysql-test/r/binlog_index.result
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
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
|
69
mysql-test/t/binlog_index.test
Normal file
69
mysql-test/t/binlog_index.test
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#
|
||||||
|
# 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
|
153
sql/log.cc
153
sql/log.cc
@ -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,
|
||||||
@ -1208,33 +1210,75 @@ int MYSQL_LOG::purge_logs(const char *to_log,
|
|||||||
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;
|
MY_STAT s;
|
||||||
if (decrease_log_space) //stat the file we want to delete
|
if (!my_stat(log_info.log_file_name, &s, MYF(0)))
|
||||||
{
|
{
|
||||||
MY_STAT s;
|
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.
|
*/
|
||||||
*/
|
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
if (my_stat(log_info.log_file_name,&s,MYF(0)))
|
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
|
||||||
file_size= s.st_size;
|
log_info.log_file_name);
|
||||||
else
|
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
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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 (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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
It's not fatal if we can't delete a log file ;
|
|
||||||
if we could delete it, take its size into account
|
|
||||||
*/
|
|
||||||
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
|
|
||||||
if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space)
|
|
||||||
*decrease_log_space-= file_size;
|
|
||||||
if (find_next_log(&log_info, 0) || exit_loop)
|
if (find_next_log(&log_info, 0) || exit_loop)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If we get killed -9 here, the sysadmin would have to edit
|
If we get killed -9 here, the sysadmin would have to edit
|
||||||
the log index file after restart - otherwise, this should be safe
|
the log index file after restart - otherwise, this should be safe
|
||||||
@ -1263,6 +1307,8 @@ err:
|
|||||||
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)
|
|||||||
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)
|
||||||
break;
|
{
|
||||||
my_delete(log_info.log_file_name, MYF(0));
|
/*
|
||||||
|
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;
|
||||||
|
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
|
|||||||
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"
|
||||||
|
Reference in New Issue
Block a user