From 03aa4876e187fcb7dbae6d43170345d2a25fb0e7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Jun 2013 10:58:34 +0200 Subject: [PATCH] MDEV-4486: Allow to start old-style replication even if mysql.rpl_slave_state is unavailable If the mysql.gtid_slave_pos table is not available, we cannot load nor update the current GTID position persistently. This can happen eg. after an upgrade, before mysql_upgrade_db is run, or if the table is InnoDB and the server is restarted without the InnoDB storage engine enabled. Before, replication always failed to start if the table was unavailable. With this patch, we try to continue with old-style replication, after suitable complaints in the error log. In strict mode, or if slave is configured to use GTID, slave still refuses to start. --- .../suite/rpl/r/rpl_gtid_stop_start.result | 51 +++++++++++++ .../suite/rpl/t/rpl_gtid_stop_start.test | 75 +++++++++++++++++++ sql/rpl_gtid.cc | 12 +++ sql/slave.cc | 16 +++- 4 files changed, 152 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result b/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result index b524ab17c23..708b553e76d 100644 --- a/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result +++ b/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result @@ -59,6 +59,57 @@ OK SELECT IF(@current_pos1=@current_pos2, "OK", CONCAT(@current_pos1, " != ", @current_pos2)); IF(@current_pos1=@current_pos2, "OK", CONCAT(@current_pos1, " != ", @current_pos2)) OK +INSERT INTO t1 VALUES (6); +include/start_slave.inc +SELECT * FROM t1 ORDER BY a; +a +1 +2 +3 +4 +5 +6 +*** MDEV-4486: Allow to start old-style replication even if mysql.gtid_slave_pos is unavailable +include/stop_slave.inc +CHANGE MASTER TO master_use_gtid= no; +include/start_slave.inc +INSERT INTO t1 VALUES (7); +SELECT * FROM t1 ORDER BY a; +a +1 +2 +3 +4 +5 +6 +7 +include/stop_slave.inc +SET sql_log_bin= 0; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +SET sql_log_bin= 1; +SELECT * FROM mysql.gtid_slave_pos; +ERROR 42000: Unknown storage engine 'InnoDB' +SET sql_log_bin=0; +call mtr.add_suppression("Failed to load slave replication state from table"); +call mtr.add_suppression("Unable to load replication GTID slave state"); +SET sql_log_bin=1; +include/start_slave.inc +Warnings: +Error 1286 Unknown storage engine 'InnoDB' +INSERT INTO t1 VALUES (8); +SELECT * FROM t1 ORDER BY a; +a +1 +2 +3 +4 +5 +6 +7 +8 +SET sql_log_bin= 0; +ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM; +SET sql_log_bin= 1; include/start_slave.inc DROP TABLE t1; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test index cc1da6b3c85..05cb078558d 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test @@ -1,5 +1,6 @@ --let $rpl_topology=1->2 --source include/rpl_init.inc +--source include/have_innodb.inc --echo *** Test normal shutdown/restart of slave server configured as a GTID slave. *** @@ -116,6 +117,80 @@ SET @slave_pos2= @@GLOBAL.gtid_slave_pos; SET @current_pos2= @@GLOBAL.gtid_current_pos; SELECT IF(@slave_pos1=@slave_pos2, "OK", CONCAT(@slave_pos1, " != ", @slave_pos2)); SELECT IF(@current_pos1=@current_pos2, "OK", CONCAT(@current_pos1, " != ", @current_pos2)); + +--connection server_1 +INSERT INTO t1 VALUES (6); +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + + +--echo *** MDEV-4486: Allow to start old-style replication even if mysql.gtid_slave_pos is unavailable + +--connection server_2 +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid= no; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (7); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; +--source include/stop_slave.inc + +SET sql_log_bin= 0; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +SET sql_log_bin= 1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server 30 +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=1 --skip-innodb +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--error ER_UNKNOWN_STORAGE_ENGINE +SELECT * FROM mysql.gtid_slave_pos; +SET sql_log_bin=0; +call mtr.add_suppression("Failed to load slave replication state from table"); +call mtr.add_suppression("Unable to load replication GTID slave state"); +SET sql_log_bin=1; + +--source include/start_slave.inc +--connection server_1 +INSERT INTO t1 VALUES (8); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +# Put things back as they were. +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server 30 +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc +SET sql_log_bin= 0; +ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM; +SET sql_log_bin= 1; --source include/start_slave.inc diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index d5e9380296e..71b18e64842 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -311,6 +311,18 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, ulonglong thd_saved_option= thd->variables.option_bits; Query_tables_list lex_backup; + if (unlikely(!loaded)) + { + /* + Probably the mysql.gtid_slave_pos table is missing (eg. upgrade) or + corrupt. + + We already complained loudly about this, but we can try to continue + until the DBA fixes it. + */ + return 0; + } + if (!in_statement) mysql_reset_thd_for_next_command(thd, 0); diff --git a/sql/slave.cc b/sql/slave.cc index ac6feb16162..8cb13205f29 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3536,7 +3536,13 @@ pthread_handler_t handle_slave_io(void *arg) mi->report(ERROR_LEVEL, thd->stmt_da->sql_errno(), "Unable to load replication GTID slave state from mysql.%s: %s", rpl_gtid_slave_state_table_name.str, thd->stmt_da->message()); - goto err; + /* + If we are using old-style replication, we can continue, even though we + then will not be able to record the GTIDs we receive. But if using GTID, + we must give up. + */ + if (mi->using_gtid != Master_info::USE_GTID_NO || opt_gtid_strict_mode) + goto err; } @@ -4141,7 +4147,13 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME, rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(), "Unable to load replication GTID slave state from mysql.%s: %s", rpl_gtid_slave_state_table_name.str, thd->stmt_da->message()); - goto err; + /* + If we are using old-style replication, we can continue, even though we + then will not be able to record the GTIDs we receive. But if using GTID, + we must give up. + */ + if (mi->using_gtid != Master_info::USE_GTID_NO || opt_gtid_strict_mode) + goto err; } /* execute init_slave variable */