diff options
author | Sujatha <sujatha.sivakumar@mariadb.com> | 2020-04-14 14:49:05 +0530 |
---|---|---|
committer | Sujatha <sujatha.sivakumar@mariadb.com> | 2020-04-20 15:02:09 +0530 |
commit | de8658523584352be345f2ab0211a85e37f445d0 (patch) | |
tree | caec6f7e5ffffdc9975cbfc1c7bce574366577d3 | |
parent | 30b69e1542506ae5ec873877ded791a8f9841844 (diff) | |
download | mariadb-git-de8658523584352be345f2ab0211a85e37f445d0.tar.gz |
MDEV-21117: Avoid creation of purge index file in case the last binlog
file alone is getting truncated.
-rw-r--r-- | mysql-test/suite/binlog/r/binlog_truncate_multi_log.result | 11 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_truncate_errors.test | 95 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_truncate_multi_log.test | 34 | ||||
-rw-r--r-- | sql/log.cc | 89 |
4 files changed, 172 insertions, 57 deletions
diff --git a/mysql-test/suite/binlog/r/binlog_truncate_multi_log.result b/mysql-test/suite/binlog/r/binlog_truncate_multi_log.result index 9796a480cca..90714c79a2e 100644 --- a/mysql-test/suite/binlog/r/binlog_truncate_multi_log.result +++ b/mysql-test/suite/binlog/r/binlog_truncate_multi_log.result @@ -1,12 +1,19 @@ -SET @old_max_binlog_size= @@global.max_binlog_size; +SET @old_max_binlog_size= @@GLOBAL.max_binlog_size; SET GLOBAL max_binlog_size= 4096; call mtr.add_suppression("Can't init tc log"); call mtr.add_suppression("Aborting"); RESET MASTER; CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; -SET DEBUG_SYNC= "commit_before_update_end_pos SIGNAL con1_ready WAIT_FOR con1_go"; +FLUSH LOGS; +SET DEBUG_SYNC= "commit_after_release_LOCK_log SIGNAL con1_ready WAIT_FOR con1_go"; INSERT INTO t1 VALUES (2, REPEAT("x", 4100)); SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; +"List of binary logs" +show binary logs; +Log_name File_size +master-bin.000001 # +master-bin.000002 # +master-bin.000003 # # Kill the server "Zero rows shoule be present in table" SELECT COUNT(*) FROM t1; diff --git a/mysql-test/suite/binlog/t/binlog_truncate_errors.test b/mysql-test/suite/binlog/t/binlog_truncate_errors.test new file mode 100644 index 00000000000..36c3732975b --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_truncate_errors.test @@ -0,0 +1,95 @@ +# ==== Purpose ==== +# +# Test verifies truncation of multiple binary logs. +# +# ==== Implementation ==== +# +# Steps: +# +# ==== References ==== +# +# MDEV-21117: --tc-heuristic-recover=rollback is not replication safe + + +--source include/have_innodb.inc +--source include/not_embedded.inc +--source include/have_log_bin.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_row.inc + +SET @old_max_binlog_size= @@GLOBAL.max_binlog_size; +SET GLOBAL max_binlog_size= 4096; +call mtr.add_suppression("tc-heuristic-recover failed to open purge index file"); +call mtr.add_suppression("Can't init tc log"); +call mtr.add_suppression("Aborting"); + +RESET MASTER; + +CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; +connect(master1,localhost,root,,); +connect(master2,localhost,root,,); + +--connection master1 +# Hold insert after write to binlog and before "run_commit_ordered" in engine. +# Use "commit_after_release_LOCK_log" sync point. This point is reached after +# the binary log end position is updated which actually triggers binlog to be +# rotated. +SET DEBUG_SYNC= "commit_after_release_LOCK_log SIGNAL con1_ready WAIT_FOR con1_go"; +send INSERT INTO t1 VALUES (2, REPEAT("x", 4100)); + +--connection master2 +SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; +--echo "List of binary logs" +--source include/show_binary_logs.inc +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +--source include/kill_mysqld.inc +--source include/wait_until_disconnected.inc + +# +# Server restart +# +--echo "Test 1" +--exec echo "restart: --tc-heuristic-recover=ROLLBACK --debug-dbug=d,simulate_innodb_forget_commit_pos,fault_injection_openning_purge_index" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--enable_reconnect +--source include/wait_until_disconnected.inc + +--echo "Test 2" +--exec echo "restart: --tc-heuristic-recover=ROLLBACK --debug-dbug=d,simulate_innodb_forget_commit_pos,crash_before_sync_purge_index_file" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--enable_reconnect +--source include/wait_until_connected_again.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart: --tc-heuristic-recover=ROLLBACK --debug-dbug=d,simulate_innodb_forget_commit_pos,crash_after_sync_purge_index_file +EOF +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart: --tc-heuristic-recover=ROLLBACK --debug-dbug=d,simulate_innodb_forget_commit_pos,crash_after_index_file_resize +EOF + +--source include/wait_until_disconnected.inc +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart: --tc-heuristic-recover=ROLLBACK --debug-dbug=d,simulate_innodb_forget_commit_pos +EOF + +--source include/wait_until_disconnected.inc +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart: +EOF + +connection default; +--enable_reconnect +--source include/wait_until_connected_again.inc + +--echo "Zero rows shoule be present in table" +SELECT COUNT(*) FROM t1; + +SELECT @@GLOBAL.gtid_current_pos; + +DROP TABLE t1; +SELECT @@GLOBAL.gtid_binlog_state; + diff --git a/mysql-test/suite/binlog/t/binlog_truncate_multi_log.test b/mysql-test/suite/binlog/t/binlog_truncate_multi_log.test index 976b987d3bc..ab9b122bd3a 100644 --- a/mysql-test/suite/binlog/t/binlog_truncate_multi_log.test +++ b/mysql-test/suite/binlog/t/binlog_truncate_multi_log.test @@ -5,16 +5,17 @@ # ==== Implementation ==== # # Steps: -# 0 - Set max_binlog_size= 4096. Create a table do an insert such that the -# max_binlog_size is reached and binary log gets rotated. -# 1 - Using debug simulation make the server crash at a point where the DML +# 0 - Create a table in innodb engine and execute FLUSH LOGS command to +# generate a new binary log. +# 1 - Set max_binlog_size= 4096. Insert a row such that the max_binlog_size +# is reached and binary log gets rotated. +# 2 - Using debug simulation make the server crash at a point where the DML # transaction is written to binary log but not committed in engine. -# 2 - At the time of crash two binary logs will be there master-bin.0000001 -# and master-bin.000002. -# 3 - Restart server with --tc-heuristic-recover=ROLLBACK -# 4 - Since the prepared DML in master-bin.000001 is rolled back the first -# binlog will be truncated prior to the DML and master-bin.000002 will be -# removed. +# 3 - At the time of crash three binary logs will be there +# master-bin.0000001, master-bin.000002 and master-bin.000003. +# 4 - Restart server with --tc-heuristic-recover=ROLLBACK +# 5 - Since the prepared DML in master-bin.000002 the binary log will be +# truncated and master-bin.000003 will be removed. # # ==== References ==== # @@ -27,27 +28,30 @@ --source include/have_debug_sync.inc --source include/have_binlog_format_row.inc -SET @old_max_binlog_size= @@global.max_binlog_size; +SET @old_max_binlog_size= @@GLOBAL.max_binlog_size; SET GLOBAL max_binlog_size= 4096; - call mtr.add_suppression("Can't init tc log"); call mtr.add_suppression("Aborting"); RESET MASTER; CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; - +FLUSH LOGS; connect(master1,localhost,root,,); connect(master2,localhost,root,,); --connection master1 -# Hold insert after write to binlog and before "run_commit_ordered" in engine -SET DEBUG_SYNC= "commit_before_update_end_pos SIGNAL con1_ready WAIT_FOR con1_go"; +# Hold insert after write to binlog and before "run_commit_ordered" in engine. +# Use "commit_after_release_LOCK_log" sync point. This point is reached after +# the binary log end position is updated which actually triggers binlog to be +# rotated. +SET DEBUG_SYNC= "commit_after_release_LOCK_log SIGNAL con1_ready WAIT_FOR con1_go"; send INSERT INTO t1 VALUES (2, REPEAT("x", 4100)); --connection master2 SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; - +--echo "List of binary logs" +--source include/show_binary_logs.inc --write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect wait EOF diff --git a/sql/log.cc b/sql/log.cc index 4d4a713376a..ad16489dab7 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4744,7 +4744,7 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *reclaimed_space, } goto err; } - + error= 0; DBUG_PRINT("info",("purging %s",log_info.log_file_name)); @@ -9562,26 +9562,28 @@ bool MYSQL_BIN_LOG::truncate_and_remove_binlogs(const char *truncate_file, #ifdef HAVE_REPLICATION LOG_INFO log_info; THD *thd= current_thd; - my_off_t index_file_offset=0; + my_off_t index_file_offset= 0; File file= -1; IO_CACHE cache; MY_STAT s; my_off_t binlog_size; - if ((error= open_purge_index_file(TRUE))) - { - sql_print_error("tc-heuristic-recover failed to open purge index file."); - goto end; - } - if ((error= find_log_pos(&log_info, truncate_file, 1))) goto end; while (!(error= find_next_log(&log_info, 1))) { if (!index_file_offset) + { index_file_offset= log_info.index_file_start_offset; - if((error= register_purge_index_entry(log_info.log_file_name))) + if ((error= open_purge_index_file(TRUE)) || + DBUG_EVALUATE_IF("fault_injection_openning_purge_index", 1, 0)) + { + sql_print_error("tc-heuristic-recover failed to open purge index file."); + goto end; + } + } + if ((error= register_purge_index_entry(log_info.log_file_name))) { sql_print_error("tc-heuristic-recover failed to copy %s to register" " file.", log_info.log_file_name); @@ -9597,41 +9599,48 @@ bool MYSQL_BIN_LOG::truncate_and_remove_binlogs(const char *truncate_file, goto end; } - if (!index_file_offset) - index_file_offset= log_info.index_file_start_offset; - - if ((error= sync_purge_index_file())) + if (is_inited_purge_index_file()) { - sql_print_error("tc-heuristic-recover failed to flush purge index register " - "file."); - goto end; - } + if (!index_file_offset) + index_file_offset= log_info.index_file_start_offset; - // Trim index file - if ((error= - mysql_file_chsize(index_file.file, index_file_offset, '\n', MYF(MY_WME)) - || mysql_file_sync(index_file.file, MYF(MY_WME|MY_SYNC_FILESIZE)))) - { - sql_print_error("tc-heuristic-recover failed to trim binlog index file."); - mysql_file_close(index_file.file, MYF(MY_WME)); - goto end; - } + DBUG_EXECUTE_IF("crash_before_sync_purge_index_file", DBUG_SUICIDE();); + if ((error= sync_purge_index_file())) + { + sql_print_error("tc-heuristic-recover failed to flush purge index " + "register file."); + goto end; + } + DBUG_EXECUTE_IF("crash_after_sync_purge_index_file", DBUG_SUICIDE();); - /* Reset data in old index cache */ - if ((error= reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 1))) - { - sql_print_error("tc-heuristic-recover failed to reinit binlog index file."); - mysql_file_close(index_file.file, MYF(MY_WME)); - goto end; - } + // Trim index file + if ((error= + mysql_file_chsize(index_file.file, index_file_offset, '\n', + MYF(MY_WME)) || + mysql_file_sync(index_file.file, MYF(MY_WME|MY_SYNC_FILESIZE)))) + { + sql_print_error("tc-heuristic-recover failed to trim binlog index file."); + mysql_file_close(index_file.file, MYF(MY_WME)); + goto end; + } - /* Read each entry from purge_index_file and delete the file. */ - if (is_inited_purge_index_file() && - (error= purge_index_entry(thd, NULL, TRUE))) - { - sql_print_error("Failed to process registered files that would be purged " - "during tc-heuristic-recover=ROLLBACK."); - goto end; + DBUG_EXECUTE_IF("crash_after_index_file_resize", DBUG_SUICIDE();); + /* Reset data in old index cache */ + if ((error= reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 1))) + { + sql_print_error("tc-heuristic-recover failed to reinit binlog index " + "file."); + mysql_file_close(index_file.file, MYF(MY_WME)); + goto end; + } + + /* Read each entry from purge_index_file and delete the file. */ + if ((error= purge_index_entry(thd, NULL, TRUE))) + { + sql_print_error("Failed to process registered files that would be purged " + "during tc-heuristic-recover=ROLLBACK."); + goto end; + } } DBUG_ASSERT(truncate_pos); |