Bug #88238 BACKUP_LOCK is allowing removal of binary and relay log files
Submitted: 26 Oct 2017 15:37 Modified: 22 Dec 2017 22:27
Reporter: João Gramacho Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Locking Severity:S3 (Non-critical)
Version:8.0.3 OS:Any
Assigned to: CPU Architecture:Any

[26 Oct 2017 15:37] João Gramacho
Description:
According to BACKUP_LOCK specification, when the it is taken, no files must be created, renamed, or removed.

One exception is that new binary log files can be created, but there are no exceptions with respect to removal of binary log files.

Also, there are no exceptions related to relay log files.

This behavior can allow:
a) New relay log files to be created if necessary by the receiver thread;
b) Expired binary log files to be automatically removed after binary log rotation;
c) Unused relay log files to be automatically removed;

The item (a) should be allowed, and binary log exception should be extended to relay log.

Items (b) and (c) are issues and should be fixed.

How to repeat:
Run the following MTR test case:

--source include/master-slave.inc

CREATE TABLE t1 (c1 INT);
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_master.inc

# Save global variables to be changed during the test case
SET @saved_expire_logs_days= @@GLOBAL.expire_logs_days;
SET @saved_binlog_expire_logs_seconds= @@GLOBAL.binlog_expire_logs_seconds;

SET @@GLOBAL.expire_logs_days= 0;
SET @@GLOBAL.binlog_expire_logs_seconds= 1;

# Prevent removal of files (among other restrictions)
--source include/rpl_connection_master1.inc
LOCK INSTANCE FOR BACKUP;
--source include/rpl_connection_slave.inc
LOCK INSTANCE FOR BACKUP;
--let $s1= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1)

# Generate workload on master
--source include/rpl_connection_master.inc
--let $m1= query_get_value(SHOW MASTER STATUS, File, 1)
FLUSH LOCAL LOGS;

--let $m2= query_get_value(SHOW MASTER STATUS, File, 1)
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);
INSERT INTO t1 VALUES (3);
FLUSH LOCAL LOGS;

--let $m3= query_get_value(SHOW MASTER STATUS, File, 1)
INSERT INTO t1 VALUES (4);
INSERT INTO t1 VALUES (5);
INSERT INTO t1 VALUES (6);
FLUSH LOCAL LOGS;
INSERT INTO t1 VALUES (7);

# Ensure slave have consumed first three binary log files
--source include/sync_slave_sql_with_master.inc
--let $sN= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1)

--source include/rpl_connection_master.inc
# Take a nap to allow binary log expiration to take action
--sleep 4
FLUSH LOCAL LOGS;
INSERT INTO t1 VALUES (8);

--source include/sync_slave_sql_with_master.inc
# Relay log files should still be available
--disable_result_log
--replace_result $s1 FIRST_RELAY_LOG_FILE
--eval SHOW RELAYLOG EVENTS IN '$s1'
--replace_result $sN LAST_RELAY_LOG_FILE
--eval SHOW RELAYLOG EVENTS IN '$sn'
--enable_result_log

--source include/rpl_connection_master.inc
# Check binary log files still around: all should be still available
--let $assert_text= 1st binary log file should still be available
--let $assert_cond= "[SHOW BINARY LOGS, Log_name, 1]" = "$m1"
--source include/assert.inc
--let $assert_text= 2nd binary log file should still be available
--let $assert_cond= "[SHOW BINARY LOGS, Log_name, 2]" = "$m2"
--source include/assert.inc
--let $assert_text= 3rd binary log file should still be available
--let $assert_cond= "[SHOW BINARY LOGS, Log_name, 3]" = "$m3"
--source include/assert.inc

# Assume backup as taken at this point
--source include/rpl_connection_slave.inc
UNLOCK INSTANCE;
--source include/rpl_connection_master1.inc
UNLOCK INSTANCE;
FLUSH LOCAL LOGS;
# Expired binary log files should not be available
--let $assert_text= 1st to 3rd binary log file should be not available
--let $assert_cond= "[SHOW BINARY LOGS, Log_name, 1]" <> "$m1" AND "<1>" <> "$m2" AND "<1>" <> "$m3"
--source include/assert.inc

DROP TABLE t1;
# Unused relay log files should not be available
--source include/sync_slave_sql_with_master.inc
--disable_result_log
--replace_result $s1 FIRST_RELAY_LOG_FILE
--error ER_ERROR_WHEN_EXECUTING_COMMAND
--eval SHOW RELAYLOG EVENTS IN '$s1'
--replace_result $sN LAST_RELAY_LOG_FILE
--error ER_ERROR_WHEN_EXECUTING_COMMAND
--eval SHOW RELAYLOG EVENTS IN '$sn'
--enable_result_log

# Cleanup
--source include/rpl_connection_master.inc

# Restore changed global variables
SET @@GLOBAL.binlog_expire_logs_seconds= @saved_binlog_expire_logs_seconds;
SET @@GLOBAL.expire_logs_days= @saved_expire_logs_days;

--source include/rpl_end.inc

Suggested fix:
I suggest the creation of a function to tell if the backup lock is acquired by any thread.

Make binary log expiration to avoid purging binary log files automatically if any thread owns the backup lock.

Make relay log purge of unused relay log files to avoid purging files if any thread owns the backup lock.
[26 Oct 2017 15:52] João Gramacho
Posted by developer:
 
On bug description:

s/This behavior can allow:/The current implemented behavior allows:/
[22 Dec 2017 22:27] Paul DuBois
Posted by developer:
 
Fixed in 8.0.4, 9.0.0.

With a backup lock active, removal of binary log files and relay log
files incorrectly was permitted.