Skip to content

Commit

Permalink
PS-9132 mysql.gtid_executed persistent GTID info lost when MySQL cras…
Browse files Browse the repository at this point in the history
…h in Gtid_state::save

https://perconadev.atlassian.net/browse/PS-9132

When the server is killed before persisting the GTIDs into
mysql.gtid_executed, the subsequent crash recovery process
fails to recover gtids from the binary logs because it does
not find the "Prev_gtid_log_event" in the last binary log.
This happens because, the last binlog was created during the
previous restart but no information about Prev_gtid_log_event
was written into the file since the server was killed before
persisting to the table. The root cause here, is that the
recovery process does not parse the previous binary logs if
"Prev_gtid_log_event" was not found in the last binary log
created by the server.

This issue is fixed by parsing all previous binary logs until
a valid "Prev_gtid_log_event" is seen.
  • Loading branch information
VarunNagaraju committed May 21, 2024
1 parent 2784e80 commit f66afb4
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 1 deletion.
22 changes: 22 additions & 0 deletions mysql-test/suite/binlog/r/binlog_gtid_persistent.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
RESET MASTER;
CREATE TABLE t1 (c1 INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
SHOW BINARY LOGS;
Log_name File_size
master-bin.000001 352
SELECT * FROM mysql.gtid_executed;
source_uuid interval_start interval_end
Kill the server
# Kill the server
Restart the server only to kill it before GTID is saved during recovery process
Start the server again to see if server recovers GTIDs from binlogs and updates @@global.gtid_executed and mysql.gtid_executed table.
# restart
SELECT interval_start, interval_end from mysql.gtid_executed;
interval_start interval_end
1 1
SHOW BINARY LOGS;
Log_name File_size
master-bin.000001 352
master-bin.000002 123
master-bin.000003 194
include/assert.inc [GTID should be properly updated]
DROP TABLE t1;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--enforce-gtid-consistency --gtid-mode=ON
40 changes: 40 additions & 0 deletions mysql-test/suite/binlog/t/binlog_gtid_persistent.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# PS-9132 mysql.gtid_executed persistent GTID info lost when MySQL crash in Gtid_state::save
#
--source include/have_log_bin.inc
--source include/have_gtid.inc

RESET MASTER;
CREATE TABLE t1 (c1 INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;

SHOW BINARY LOGS;
SELECT * FROM mysql.gtid_executed;

--echo Kill the server
--source include/kill_mysqld.inc

--echo Restart the server only to kill it before GTID is saved during recovery process
--error 137
--exec $MYSQLD_CMD --debug="d,crash_before_gtid_persist"

--echo Start the server again to see if server recovers GTIDs from binlogs and updates @@global.gtid_executed and mysql.gtid_executed table.
--source include/start_mysqld.inc

SELECT interval_start, interval_end from mysql.gtid_executed;
SHOW BINARY LOGS;
#SHOW BINLOG EVENTS IN 'master-bin.000003';

# Verify if GTID_EXECUTED is updated with the Previous_gtids properly
--let $prev_gtid = query_get_value(SHOW BINLOG EVENTS in 'master-bin.000003', Info, 2)
--let $gtid_executed = `SELECT @@GLOBAL.GTID_EXECUTED`
if($prev_gtid == '') {
die "Could not find Previous_gtid_log_event in the last binary log parsed by the server";
}
if($gtid_executed == '') {
die "Server could not recover GTIDs from binary logs during recovery";
}
--let $assert_text = GTID should be properly updated
--let $assert_cond = "$prev_gtid" = "$gtid_executed"
--source include/assert.inc

#Cleanup
DROP TABLE t1;
2 changes: 1 addition & 1 deletion sql/binlog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4981,7 +4981,7 @@ bool MYSQL_BIN_LOG::init_gtid_sets(Gtid_set *all_gtids, Gtid_set *lost_gtids,
GLOBAL.GTID_PURGED should be empty in the case.
*/
if (binlog_gtid_simple_recovery && is_server_starting &&
!is_relay_log)
!is_relay_log && reached_first_file)
{
assert(all_gtids->is_empty());
assert(lost_gtids->is_empty());
Expand Down
1 change: 1 addition & 0 deletions sql/rpl_gtid_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ int Gtid_state::save(THD *thd)
int Gtid_state::save(const Gtid_set *gtid_set)
{
DBUG_ENTER("Gtid_state::save(Gtid_set *gtid_set)");
DBUG_EXECUTE_IF("crash_before_gtid_persist", DBUG_SUICIDE(););
int ret= gtid_table_persistor->save(gtid_set);
DBUG_RETURN(ret);
}
Expand Down

0 comments on commit f66afb4

Please sign in to comment.