mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
MDEV-26: Global transaction ID.
Fix error handling when record_gtid() fails to update the mysql.rpl_slave_state table.
This commit is contained in:
parent
e590f89114
commit
b6b84d6825
5 changed files with 108 additions and 30 deletions
|
@ -7,21 +7,21 @@ ALTER TABLE mysql.rpl_slave_state CHANGE seq_no seq_no VARCHAR(20);
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
CALL mtr.add_suppression("Slave: Failed to open mysql.rpl_slave_state");
|
CALL mtr.add_suppression("Slave: Failed to open mysql.rpl_slave_state");
|
||||||
include/wait_for_slave_sql_error.inc [errno=1943]
|
include/wait_for_slave_sql_error.inc [errno=1941]
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
ALTER TABLE mysql.rpl_slave_state CHANGE seq_no seq_no BIGINT UNSIGNED NOT NULL;
|
ALTER TABLE mysql.rpl_slave_state CHANGE seq_no seq_no BIGINT UNSIGNED NOT NULL;
|
||||||
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
||||||
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id, domain_id);
|
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id, domain_id);
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1943]
|
include/wait_for_slave_sql_error.inc [errno=1941]
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1943]
|
include/wait_for_slave_sql_error.inc [errno=1941]
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id);
|
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id);
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1943]
|
include/wait_for_slave_sql_error.inc [errno=1941]
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
||||||
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (domain_id, sub_id);
|
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (domain_id, sub_id);
|
||||||
|
@ -85,5 +85,23 @@ START SLAVE;
|
||||||
SET sql_log_bin=0;
|
SET sql_log_bin=0;
|
||||||
CALL mtr.add_suppression("The slave I/O thread stops because master does not support MariaDB global transaction id");
|
CALL mtr.add_suppression("The slave I/O thread stops because master does not support MariaDB global transaction id");
|
||||||
SET sql_log_bin=1;
|
SET sql_log_bin=1;
|
||||||
|
*** Test error during record_gtid() (non-xid cases) ***
|
||||||
|
include/stop_slave.inc
|
||||||
|
CREATE TABLE t2 (a INT) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
SET @old_dbug= @@global.DEBUG_DBUG;
|
||||||
|
SET GLOBAL debug_dbug="+d,gtid_inject_record_gtid";
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_sql_error.inc [errno=1941]
|
||||||
|
SET GLOBAL debug_dbug= @old_dbug;
|
||||||
|
START SLAVE SQL_THREAD;
|
||||||
|
SELECT * FROM t2;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
1
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
CALL mtr.add_suppression("Slave: Could not update replication slave gtid state");
|
||||||
|
SET sql_log_bin=1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
include/rpl_end.inc
|
include/rpl_end.inc
|
||||||
|
|
|
@ -16,7 +16,7 @@ INSERT INTO t1 VALUES (1);
|
||||||
|
|
||||||
--connection slave
|
--connection slave
|
||||||
CALL mtr.add_suppression("Slave: Failed to open mysql.rpl_slave_state");
|
CALL mtr.add_suppression("Slave: Failed to open mysql.rpl_slave_state");
|
||||||
--let $slave_sql_errno=1943
|
--let $slave_sql_errno=1941
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
--source include/stop_slave.inc
|
--source include/stop_slave.inc
|
||||||
|
@ -24,19 +24,19 @@ ALTER TABLE mysql.rpl_slave_state CHANGE seq_no seq_no BIGINT UNSIGNED NOT NULL;
|
||||||
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
||||||
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id, domain_id);
|
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id, domain_id);
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
--let $slave_sql_errno=1943
|
--let $slave_sql_errno=1941
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
--source include/stop_slave.inc
|
--source include/stop_slave.inc
|
||||||
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
--let $slave_sql_errno=1943
|
--let $slave_sql_errno=1941
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
--source include/stop_slave.inc
|
--source include/stop_slave.inc
|
||||||
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id);
|
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id);
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
--let $slave_sql_errno=1943
|
--let $slave_sql_errno=1941
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
--source include/stop_slave.inc
|
--source include/stop_slave.inc
|
||||||
|
@ -134,7 +134,37 @@ CALL mtr.add_suppression("The slave I/O thread stops because master does not sup
|
||||||
SET sql_log_bin=1;
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo *** Test error during record_gtid() (non-xid cases) ***
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
|
||||||
|
--connection master
|
||||||
|
CREATE TABLE t2 (a INT) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
--save_master_pos
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
SET @old_dbug= @@global.DEBUG_DBUG;
|
||||||
|
SET GLOBAL debug_dbug="+d,gtid_inject_record_gtid";
|
||||||
|
|
||||||
|
START SLAVE;
|
||||||
|
--let $slave_sql_errno= 1941
|
||||||
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
|
SET GLOBAL debug_dbug= @old_dbug;
|
||||||
|
|
||||||
|
START SLAVE SQL_THREAD;
|
||||||
|
--sync_with_master
|
||||||
|
|
||||||
|
SELECT * FROM t2;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
CALL mtr.add_suppression("Slave: Could not update replication slave gtid state");
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
|
|
||||||
--connection master
|
--connection master
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
|
||||||
--source include/rpl_end.inc
|
--source include/rpl_end.inc
|
||||||
|
|
|
@ -3814,26 +3814,6 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
|
||||||
*/
|
*/
|
||||||
const_cast<Relay_log_info*>(rli)->inc_event_relay_log_pos();
|
const_cast<Relay_log_info*>(rli)->inc_event_relay_log_pos();
|
||||||
const_cast<Relay_log_info*>(rli)->clear_flag(Relay_log_info::IN_STMT);
|
const_cast<Relay_log_info*>(rli)->clear_flag(Relay_log_info::IN_STMT);
|
||||||
|
|
||||||
/*
|
|
||||||
Record any GTID in the same transaction, so slave state is
|
|
||||||
transactionally consistent.
|
|
||||||
*/
|
|
||||||
if ((sub_id= rli->gtid_sub_id))
|
|
||||||
{
|
|
||||||
/* Clear the GTID from the RLI so we don't accidentally reuse it. */
|
|
||||||
const_cast<Relay_log_info*>(rli)->gtid_sub_id= 0;
|
|
||||||
|
|
||||||
gtid= rli->current_gtid;
|
|
||||||
error= rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true);
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
my_error(ER_CANNOT_UPDATE_GTID_STATE, MYF(0));
|
|
||||||
trans_rollback(thd);
|
|
||||||
sub_id= 0;
|
|
||||||
goto compare_errors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3958,6 +3938,30 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
|
||||||
else
|
else
|
||||||
thd->variables.collation_database= thd->db_charset;
|
thd->variables.collation_database= thd->db_charset;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Record any GTID in the same transaction, so slave state is
|
||||||
|
transactionally consistent.
|
||||||
|
*/
|
||||||
|
if (strcmp("COMMIT", query) == 0 && (sub_id= rli->gtid_sub_id))
|
||||||
|
{
|
||||||
|
/* Clear the GTID from the RLI so we don't accidentally reuse it. */
|
||||||
|
const_cast<Relay_log_info*>(rli)->gtid_sub_id= 0;
|
||||||
|
|
||||||
|
gtid= rli->current_gtid;
|
||||||
|
if (rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true))
|
||||||
|
{
|
||||||
|
rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE,
|
||||||
|
"Error during COMMIT: failed to update GTID state in "
|
||||||
|
"%s.%s: %d: %s",
|
||||||
|
"mysql", rpl_gtid_slave_state_table_name.str,
|
||||||
|
thd->stmt_da->sql_errno(), thd->stmt_da->message());
|
||||||
|
trans_rollback(thd);
|
||||||
|
sub_id= 0;
|
||||||
|
thd->is_slave_error= 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
thd->table_map_for_update= (table_map)table_map_for_update;
|
thd->table_map_for_update= (table_map)table_map_for_update;
|
||||||
thd->set_invoker(&user, &host);
|
thd->set_invoker(&user, &host);
|
||||||
/*
|
/*
|
||||||
|
@ -6842,7 +6846,13 @@ int Xid_log_event::do_apply_event(Relay_log_info const *rli)
|
||||||
err= rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true);
|
err= rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
|
rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE,
|
||||||
|
"Error during XID COMMIT: failed to update GTID state in "
|
||||||
|
"%s.%s: %d: %s",
|
||||||
|
"mysql", rpl_gtid_slave_state_table_name.str,
|
||||||
|
thd->stmt_da->sql_errno(), thd->stmt_da->message());
|
||||||
trans_rollback(thd);
|
trans_rollback(thd);
|
||||||
|
thd->is_slave_error= 1;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
|
|
||||||
const LEX_STRING rpl_gtid_slave_state_table_name=
|
const LEX_STRING rpl_gtid_slave_state_table_name=
|
||||||
{ STRING_WITH_LEN("rpl_slave_state") };
|
{ C_STRING_WITH_LEN("rpl_slave_state") };
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -298,6 +298,12 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
||||||
|
|
||||||
mysql_reset_thd_for_next_command(thd, 0);
|
mysql_reset_thd_for_next_command(thd, 0);
|
||||||
|
|
||||||
|
DBUG_EXECUTE_IF("gtid_inject_record_gtid",
|
||||||
|
{
|
||||||
|
my_error(ER_CANNOT_UPDATE_GTID_STATE, MYF(0));
|
||||||
|
return 1;
|
||||||
|
} );
|
||||||
|
|
||||||
tlist.init_one_table(STRING_WITH_LEN("mysql"),
|
tlist.init_one_table(STRING_WITH_LEN("mysql"),
|
||||||
rpl_gtid_slave_state_table_name.str,
|
rpl_gtid_slave_state_table_name.str,
|
||||||
rpl_gtid_slave_state_table_name.length,
|
rpl_gtid_slave_state_table_name.length,
|
||||||
|
@ -328,6 +334,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
||||||
if ((elem= get_element(gtid->domain_id)) == NULL)
|
if ((elem= get_element(gtid->domain_id)) == NULL)
|
||||||
{
|
{
|
||||||
unlock();
|
unlock();
|
||||||
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||||
err= 1;
|
err= 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1232,7 +1232,20 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inc_group_relay_log_pos(event_master_log_pos);
|
inc_group_relay_log_pos(event_master_log_pos);
|
||||||
rpl_global_gtid_slave_state.record_and_update_gtid(thd, this);
|
if (rpl_global_gtid_slave_state.record_and_update_gtid(thd, this))
|
||||||
|
{
|
||||||
|
report(WARNING_LEVEL, ER_CANNOT_UPDATE_GTID_STATE,
|
||||||
|
"Failed to update GTID state in %s.%s, slave state may become "
|
||||||
|
"inconsistent: %d: %s",
|
||||||
|
"mysql", rpl_gtid_slave_state_table_name.str,
|
||||||
|
thd->stmt_da->sql_errno(), thd->stmt_da->message());
|
||||||
|
/*
|
||||||
|
At this point we are not in a transaction (for example after DDL),
|
||||||
|
so we can not roll back. Anyway, normally updates to the slave
|
||||||
|
state table should not fail, and if they do, at least we made the
|
||||||
|
DBA aware of the problem in the error log.
|
||||||
|
*/
|
||||||
|
}
|
||||||
flush_relay_log_info(this);
|
flush_relay_log_info(this);
|
||||||
/*
|
/*
|
||||||
Note that Rotate_log_event::do_apply_event() does not call this
|
Note that Rotate_log_event::do_apply_event() does not call this
|
||||||
|
|
Loading…
Add table
Reference in a new issue