summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSujatha <sujatha.sivakumar@mariadb.com>2020-04-14 14:49:05 +0530
committerSujatha <sujatha.sivakumar@mariadb.com>2020-04-20 15:02:09 +0530
commitde8658523584352be345f2ab0211a85e37f445d0 (patch)
treecaec6f7e5ffffdc9975cbfc1c7bce574366577d3
parent30b69e1542506ae5ec873877ded791a8f9841844 (diff)
downloadmariadb-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.result11
-rw-r--r--mysql-test/suite/binlog/t/binlog_truncate_errors.test95
-rw-r--r--mysql-test/suite/binlog/t/binlog_truncate_multi_log.test34
-rw-r--r--sql/log.cc89
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);