From b978a14c6ed4d6ecb750ea186fe20fc489a5a296 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Aug 2013 12:51:09 +0200 Subject: [PATCH] MDEV-4650: show variables; ERROR 1946 (HY000): Failed to load replication slave GTID position The bug was that if mysql.slave_gtid_pos was missing, operations on variables gtid_slave_pos, gtid_binlog_pos, and gtid_current_pos would fail, and continue to fail even after the table was fixed, until server restart. Now setting the variables retry loading the table, succeeding if it has been restored. And querying the variables when the table is not there acts as if the table was there and was empty. Also, attempt to fix a race in the rpl.rpl_gtid_basic test case. --- .../suite/rpl/r/rpl_gtid_stop_start.result | 26 ++++++++++ mysql-test/suite/rpl/t/rpl_gtid_basic.test | 8 ++- .../suite/rpl/t/rpl_gtid_stop_start.test | 51 +++++++++++++++++++ sql/sys_vars.cc | 38 ++++++++------ 4 files changed, 105 insertions(+), 18 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 6d607ff0277..61c2fc0a0e9 100644 --- a/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result +++ b/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result @@ -155,5 +155,31 @@ SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id; domain_id COUNT(*) 0 2 1 2 +*** MDEV-4650: show variables; ERROR 1946 (HY000): Failed to load replication slave GTID position *** +SET sql_log_bin=0; +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_old; +SET sql_log_bin=1; +SHOW VARIABLES; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos +SET GLOBAL gtid_slave_pos = '0-1-2'; +Got one of the listed errors +SHOW WARNINGS; +Level Code Message +Error 1146 Table 'mysql.gtid_slave_pos' doesn't exist +Error 1946 Failed to load replication slave GTID position from table mysql.gtid_slave_pos +SET sql_log_bin=0; +RENAME TABLE mysql.gtid_slave_pos_old TO mysql.gtid_slave_pos; +CALL mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos"); +SET sql_log_bin=1; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos +SET GLOBAL gtid_slave_pos = '0-1-2'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos 0-1-2 +include/start_slave.inc DROP TABLE t1; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_basic.test b/mysql-test/suite/rpl/t/rpl_gtid_basic.test index 17d03ddc90c..37f7886118a 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_basic.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_basic.test @@ -191,11 +191,15 @@ SET GLOBAL gtid_binlog_state = @old_state; CREATE TABLE t1 (a INT PRIMARY KEY); INSERT INTO t1 VALUES (1); ---save_master_pos +--let $master_pos= `SELECT @@GLOBAL.gtid_binlog_pos` --connection server_2 --source include/start_slave.inc ---sync_with_master +# We cannot just use sync_with_master as we've done RESET MASTER, so +# slave old-style position is wrong. +# So sync on gtid position instead. +--let $wait_condition= SELECT @@GLOBAL.gtid_binlog_pos = '$master_pos' +--source include/wait_condition.inc SELECT * FROM t1; 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 fda310db0da..925095c852b 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test @@ -273,6 +273,57 @@ INSERT INTO t1 VALUES (13); SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id; +--echo *** MDEV-4650: show variables; ERROR 1946 (HY000): Failed to load replication slave GTID position *** + +--connection server_2 +SET sql_log_bin=0; +--let $old_pos= `SELECT @@GLOBAL.gtid_slave_pos` +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_old; +SET sql_log_bin=1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server 30 +--source include/wait_until_disconnected.inc + +# Let the slave mysqld server start again. +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--disable_result_log +SHOW VARIABLES; +--enable_result_log +SHOW VARIABLES LIKE 'gtid_slave_pos'; +--error ER_CANNOT_LOAD_SLAVE_GTID_STATE,ER_NO_SUCH_TABLE +SET GLOBAL gtid_slave_pos = '0-1-2'; +SHOW WARNINGS; + +# Restore things. + +SET sql_log_bin=0; +RENAME TABLE mysql.gtid_slave_pos_old TO mysql.gtid_slave_pos; +CALL mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos"); +SET sql_log_bin=1; + +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SET GLOBAL gtid_slave_pos = '0-1-2'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; + +# Don't let .result file depend on old state of gtid_slave_pos +--disable_query_log +--disable_result_log +eval SET GLOBAL gtid_slave_pos = '$old_pos'; +--enable_query_log +--enable_result_log + +--source include/start_slave.inc + + --connection server_1 DROP TABLE t1; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 3827e3f4b67..3dc6ba88293 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1282,12 +1282,6 @@ Sys_var_gtid_binlog_pos::global_value_ptr(THD *thd, LEX_STRING *base) String str(buf, sizeof(buf), system_charset_info); char *p; - if (!rpl_global_gtid_slave_state.loaded) - { - my_error(ER_CANNOT_LOAD_SLAVE_GTID_STATE, MYF(0), "mysql", - rpl_gtid_slave_state_table_name.str); - return NULL; - } str.length(0); if ((opt_bin_log && mysql_bin_log.append_state_pos(&str)) || !(p= thd->strmake(str.ptr(), str.length()))) @@ -1316,7 +1310,17 @@ Sys_var_gtid_current_pos::global_value_ptr(THD *thd, LEX_STRING *base) char *p; str.length(0); - if (rpl_append_gtid_state(&str, true) || + + /* + If the mysql.rpl_slave_pos table could not be loaded, then we cannot + easily automatically try to reload it here - we may be inside a statement + that already has tables locked and so opening more tables is problematic. + + But if the table is not loaded (eg. missing mysql_upgrade_db or some such), + then the slave state must be empty anyway. + */ + if ((rpl_global_gtid_slave_state.loaded && + rpl_append_gtid_state(&str, true)) || !(p= thd->strmake(str.ptr(), str.length()))) { my_error(ER_OUT_OF_RESOURCES, MYF(0)); @@ -1335,7 +1339,7 @@ Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var) DBUG_ASSERT(var->type == OPT_GLOBAL); - if (!rpl_global_gtid_slave_state.loaded) + if (rpl_load_gtid_slave_state(thd)) { my_error(ER_CANNOT_LOAD_SLAVE_GTID_STATE, MYF(0), "mysql", rpl_gtid_slave_state_table_name.str); @@ -1400,15 +1404,17 @@ Sys_var_gtid_slave_pos::global_value_ptr(THD *thd, LEX_STRING *base) String str; char *p; - if (!rpl_global_gtid_slave_state.loaded) - { - my_error(ER_CANNOT_LOAD_SLAVE_GTID_STATE, MYF(0), "mysql", - rpl_gtid_slave_state_table_name.str); - return NULL; - } - str.length(0); - if (rpl_append_gtid_state(&str, false) || + /* + If the mysql.rpl_slave_pos table could not be loaded, then we cannot + easily automatically try to reload it here - we may be inside a statement + that already has tables locked and so opening more tables is problematic. + + But if the table is not loaded (eg. missing mysql_upgrade_db or some such), + then the slave state must be empty anyway. + */ + if ((rpl_global_gtid_slave_state.loaded && + rpl_append_gtid_state(&str, false)) || !(p= thd->strmake(str.ptr(), str.length()))) { my_error(ER_OUT_OF_RESOURCES, MYF(0));