Commit b978a14c authored by unknown's avatar unknown

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.
parent f9c2b402
...@@ -155,5 +155,31 @@ SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id; ...@@ -155,5 +155,31 @@ SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id;
domain_id COUNT(*) domain_id COUNT(*)
0 2 0 2
1 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; DROP TABLE t1;
include/rpl_end.inc include/rpl_end.inc
...@@ -191,11 +191,15 @@ SET GLOBAL gtid_binlog_state = @old_state; ...@@ -191,11 +191,15 @@ SET GLOBAL gtid_binlog_state = @old_state;
CREATE TABLE t1 (a INT PRIMARY KEY); CREATE TABLE t1 (a INT PRIMARY KEY);
INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (1);
--save_master_pos --let $master_pos= `SELECT @@GLOBAL.gtid_binlog_pos`
--connection server_2 --connection server_2
--source include/start_slave.inc --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; SELECT * FROM t1;
......
...@@ -273,6 +273,57 @@ INSERT INTO t1 VALUES (13); ...@@ -273,6 +273,57 @@ INSERT INTO t1 VALUES (13);
SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id; 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 --connection server_1
DROP TABLE t1; DROP TABLE t1;
......
...@@ -1282,12 +1282,6 @@ Sys_var_gtid_binlog_pos::global_value_ptr(THD *thd, LEX_STRING *base) ...@@ -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); String str(buf, sizeof(buf), system_charset_info);
char *p; 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); str.length(0);
if ((opt_bin_log && mysql_bin_log.append_state_pos(&str)) || if ((opt_bin_log && mysql_bin_log.append_state_pos(&str)) ||
!(p= thd->strmake(str.ptr(), str.length()))) !(p= thd->strmake(str.ptr(), str.length())))
...@@ -1316,7 +1310,17 @@ Sys_var_gtid_current_pos::global_value_ptr(THD *thd, LEX_STRING *base) ...@@ -1316,7 +1310,17 @@ Sys_var_gtid_current_pos::global_value_ptr(THD *thd, LEX_STRING *base)
char *p; char *p;
str.length(0); 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()))) !(p= thd->strmake(str.ptr(), str.length())))
{ {
my_error(ER_OUT_OF_RESOURCES, MYF(0)); my_error(ER_OUT_OF_RESOURCES, MYF(0));
...@@ -1335,7 +1339,7 @@ Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var) ...@@ -1335,7 +1339,7 @@ Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var)
DBUG_ASSERT(var->type == OPT_GLOBAL); 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", my_error(ER_CANNOT_LOAD_SLAVE_GTID_STATE, MYF(0), "mysql",
rpl_gtid_slave_state_table_name.str); rpl_gtid_slave_state_table_name.str);
...@@ -1400,15 +1404,17 @@ Sys_var_gtid_slave_pos::global_value_ptr(THD *thd, LEX_STRING *base) ...@@ -1400,15 +1404,17 @@ Sys_var_gtid_slave_pos::global_value_ptr(THD *thd, LEX_STRING *base)
String str; String str;
char *p; 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); 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()))) !(p= thd->strmake(str.ptr(), str.length())))
{ {
my_error(ER_OUT_OF_RESOURCES, MYF(0)); my_error(ER_OUT_OF_RESOURCES, MYF(0));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment