1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-41214: PURGE BINARY LOGS does not delete non-active binlog files

Make the binlog-in-engine code path ignore
@@slave_connections_needed_for_purge for interactive PURGE BINARY
LOGS.

Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
This commit is contained in:
Kristian Nielsen
2026-10-14 11:58:26 +02:00
parent 07c5db8894
commit c81dffd460
6 changed files with 113 additions and 49 deletions

View File

@@ -36,16 +36,22 @@ RESET MASTER;
--echo #
FLUSH BINARY LOGS;
FLUSH BINARY LOGS;
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
FLUSH BINARY LOGS;
if ($binlog_in_engine) {
--let $binlog_name= binlog-000004.ibb
--let $binlog_size= 262144
--source include/wait_for_engine_binlog.inc
}
--source include/show_binary_logs.inc
PURGE BINARY LOGS TO 'master-bin.000003';
eval PURGE BINARY LOGS TO '$binlog_file';
SHOW WARNINGS;
--source include/show_binary_logs.inc
--let $first= query_get_value(SHOW BINARY LOGS, Log_name, 1)
if ($first != master-bin.000003)
if ($first != $binlog_file)
{
--echo # Control failed: expected master-bin.000003 first, got $first
--echo # Control failed: expected $binlog_file first, got $first
--die Interactive purge did not work even with no cached refusal
}
@@ -55,7 +61,12 @@ if ($first != master-bin.000003)
--echo #
FLUSH BINARY LOGS;
FLUSH BINARY LOGS;
--let $binlog_file2= query_get_value(SHOW MASTER STATUS, File, 1)
FLUSH BINARY LOGS;
if ($binlog_in_engine) {
--let $binlog_name= binlog-000007.ibb
--source include/wait_for_engine_binlog.inc
}
--source include/show_binary_logs.inc
--echo # Let the files age past binlog_expire_logs_seconds: purge_logs_before_date
@@ -65,23 +76,30 @@ SET @@global.binlog_expire_logs_seconds= 1;
--echo # Rotating attempts an automatic purge, which the guard refuses. That
--echo # refusal is what populates the cache.
FLUSH BINARY LOGS;
--let $binlog_file3= query_get_value(SHOW MASTER STATUS, File, 1)
--let $first= query_get_value(SHOW BINARY LOGS, Log_name, 1)
if ($first != master-bin.000003)
if ($first != $binlog_file)
{
--echo # Setup failed: expected the automatic purge to delete nothing.
--die The automatic purge was not refused, so nothing was cached
}
--echo # The automatic refusal states the correct reason in the error log:
--let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let SEARCH_PATTERN= Binary log .master-bin.000003. is not purged because less than .slave_connections_needed_for_purge. slaves have processed it
--source include/search_pattern_in_file.inc
if (!$binlog_in_engine) {
--echo # The automatic refusal states the correct reason in the error log:
--let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let SEARCH_PATTERN= Binary log .$binlog_file. is not purged because less than .slave_connections_needed_for_purge. slaves have processed it
--source include/search_pattern_in_file.inc
}
--echo # Now the interactive purge. It should behave exactly as in part 1.
PURGE BINARY LOGS TO 'master-bin.000006';
--echo # On affected versions this reports master-bin.000003 as the current active
--echo # binlog, while master-bin.000008 is active:
eval PURGE BINARY LOGS TO '$binlog_file2';
--echo # On affected versions this reports $binlog_file as the current active
--echo # binlog, while $binlog_file3 is active:
SHOW WARNINGS;
if ($binlog_in_engine) {
--let $binlog_name= binlog-000008.ibb
--source include/wait_for_engine_binlog.inc
}
--source include/show_binary_logs.inc
--evalp SET @@global.binlog_expire_logs_seconds = $save_binlog_expire_logs_seconds

View File

@@ -36,14 +36,6 @@ INSERT INTO t1 VALUES (100);
INSERT INTO t2 VALUES (100, 'xyzzy');
DROP TABLE t1, t2;
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(2048)) ENGINE=InnoDB;
SET @old_min_slaves= @@GLOBAL.slave_connections_needed_for_purge;
SET GLOBAL slave_connections_needed_for_purge= 1;
PURGE BINARY LOGS TO 'binlog-000001.ibb';
ERROR HY000: A purgeable log is in use, will not purge
SHOW WARNINGS;
Level Code Message
Note 1375 Binary log 'binlog-000000.ibb' is not purged because less than 'slave_connections_needed_for_purge' slaves have processed it
Error 1378 A purgeable log is in use, will not purge
SET GLOBAL slave_connections_needed_for_purge= 0;
PURGE BINARY LOGS TO 'binlog-000001.ibb';
ERROR HY000: A purgeable log is in use, will not purge

View File

@@ -65,11 +65,6 @@ DROP TABLE t1, t2;
# Test purge by size
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(2048)) ENGINE=InnoDB;
SET @old_min_slaves= @@GLOBAL.slave_connections_needed_for_purge;
SET GLOBAL slave_connections_needed_for_purge= 1;
--error ER_LOG_IN_USE
PURGE BINARY LOGS TO 'binlog-000001.ibb';
SHOW WARNINGS;
SET GLOBAL slave_connections_needed_for_purge= 0;
--error ER_LOG_IN_USE
PURGE BINARY LOGS TO 'binlog-000001.ibb';

View File

@@ -0,0 +1,74 @@
SET @@global.binlog_expire_logs_seconds= 0;
SET @@global.max_binlog_total_size= 0;
SET @@global.slave_connections_needed_for_purge= 1;
SELECT @@global.slave_connections_needed_for_purge;
@@global.slave_connections_needed_for_purge
1
SELECT @@global.binlog_expire_logs_seconds, @@global.max_binlog_total_size;
@@global.binlog_expire_logs_seconds @@global.max_binlog_total_size
0 0
# No replica has ever connected:
SELECT COUNT(*) AS dump_threads FROM information_schema.PROCESSLIST
WHERE COMMAND = 'Binlog Dump';
dump_threads
0
RESET MASTER;
#
# Part 1 (control). Nothing has attempted a purge yet, so no refusal is
# cached, and the interactive purge correctly ignores the slave's guard.
#
FLUSH BINARY LOGS;
FLUSH BINARY LOGS;
FLUSH BINARY LOGS;
show binary logs;
Log_name File_size
binlog-000000.ibb #
binlog-000001.ibb #
binlog-000002.ibb #
binlog-000003.ibb #
binlog-000004.ibb #
PURGE BINARY LOGS TO 'binlog-000002.ibb';
SHOW WARNINGS;
Level Code Message
show binary logs;
Log_name File_size
binlog-000002.ibb #
binlog-000003.ibb #
binlog-000004.ibb #
#
# Part 2. Let one automatic purge be refused, then try PURGE that must
# be effective on the fixed server.
#
FLUSH BINARY LOGS;
FLUSH BINARY LOGS;
FLUSH BINARY LOGS;
show binary logs;
Log_name File_size
binlog-000002.ibb #
binlog-000003.ibb #
binlog-000004.ibb #
binlog-000005.ibb #
binlog-000006.ibb #
binlog-000007.ibb #
# Let the files age past binlog_expire_logs_seconds: purge_logs_before_date
# skips can_purge_log() for any file whose mtime is not older than that.
SET @@global.binlog_expire_logs_seconds= 1;
# Rotating attempts an automatic purge, which the guard refuses. That
# refusal is what populates the cache.
FLUSH BINARY LOGS;
# Now the interactive purge. It should behave exactly as in part 1.
PURGE BINARY LOGS TO 'binlog-000005.ibb';
# On affected versions this reports binlog-000002.ibb as the current active
# binlog, while binlog-000007.ibb is active:
SHOW WARNINGS;
Level Code Message
show binary logs;
Log_name File_size
binlog-000005.ibb #
binlog-000006.ibb #
binlog-000007.ibb #
binlog-000008.ibb #
SET @@global.binlog_expire_logs_seconds = $save_binlog_expire_logs_seconds;
SET @@global.max_binlog_total_size= $save_max_binlog_total_size;
SET @@global.slave_connections_needed_for_purge= $save_slave_connections_needed_for_purge;
RESET MASTER;

View File

@@ -0,0 +1,4 @@
--let $binlog_in_engine= 1
--source suite/binlog/t/binlog_purge_stale_refusal_cache.test
# This is last so we override the --log-bin server option correctly.
--source include/have_innodb_binlog.inc

View File

@@ -838,22 +838,9 @@ bool purge_master_logs(THD* thd, const char* to_log)
handler_binlog_purge_info purge_info;
auto p= engine_binlog_in_use();
purge_info.limit_file_no= p.first;
uint num_dump_threads= p.second;
if (num_dump_threads < slave_connections_needed_for_purge)
{
/*
Prevent purging any file.
We need to do it this way, since we have to call into the engine to let
it check if there are any files to potentially purge. If there are, we
want to give an error that purge was not possible. But if there were no
files to purge in any case, we do not want to give any error.
*/
purge_info.limit_file_no= 0;
purge_info.nonpurge_reason= "less than "
"'slave_connections_needed_for_purge' slaves have processed it";
}
else
purge_info.nonpurge_reason= nullptr;
uint num_dump_threads __attribute__((unused))= p.second;
/* Interactive purge ignores slave_connections_needed_for_purge */
purge_info.nonpurge_reason= nullptr;
purge_info.nonpurge_filename[0]= '\0';
purge_info.purge_by_date= false;
purge_info.limit_date= (time_t)0;
@@ -901,15 +888,9 @@ bool purge_master_logs_before_date(THD* thd, time_t purge_time)
handler_binlog_purge_info purge_info;
auto p= engine_binlog_in_use();
purge_info.limit_file_no= p.first;
uint num_dump_threads= p.second;
if (num_dump_threads < slave_connections_needed_for_purge)
{
purge_info.limit_file_no= 0;
purge_info.nonpurge_reason= "less than "
"'slave_connections_needed_for_purge' slaves have processed it";
}
else
purge_info.nonpurge_reason= nullptr;
uint num_dump_threads __attribute__((unused))= p.second;
/* Interactive purge ignores slave_connections_needed_for_purge */
purge_info.nonpurge_reason= nullptr;
purge_info.nonpurge_filename[0]= '\0';
purge_info.purge_by_date= true;
purge_info.limit_date= purge_time;