mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +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;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
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
|
||||
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 ADD PRIMARY KEY (sub_id, domain_id);
|
||||
START SLAVE;
|
||||
include/wait_for_slave_sql_error.inc [errno=1943]
|
||||
include/wait_for_slave_sql_error.inc [errno=1941]
|
||||
include/stop_slave.inc
|
||||
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
||||
START SLAVE;
|
||||
include/wait_for_slave_sql_error.inc [errno=1943]
|
||||
include/wait_for_slave_sql_error.inc [errno=1941]
|
||||
include/stop_slave.inc
|
||||
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id);
|
||||
START SLAVE;
|
||||
include/wait_for_slave_sql_error.inc [errno=1943]
|
||||
include/wait_for_slave_sql_error.inc [errno=1941]
|
||||
include/stop_slave.inc
|
||||
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
||||
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (domain_id, sub_id);
|
||||
|
@ -85,5 +85,23 @@ START SLAVE;
|
|||
SET sql_log_bin=0;
|
||||
CALL mtr.add_suppression("The slave I/O thread stops because master does not support MariaDB global transaction id");
|
||||
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 t2;
|
||||
include/rpl_end.inc
|
||||
|
|
|
@ -16,7 +16,7 @@ INSERT INTO t1 VALUES (1);
|
|||
|
||||
--connection slave
|
||||
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/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 ADD PRIMARY KEY (sub_id, domain_id);
|
||||
START SLAVE;
|
||||
--let $slave_sql_errno=1943
|
||||
--let $slave_sql_errno=1941
|
||||
--source include/wait_for_slave_sql_error.inc
|
||||
|
||||
--source include/stop_slave.inc
|
||||
ALTER TABLE mysql.rpl_slave_state DROP PRIMARY KEY;
|
||||
START SLAVE;
|
||||
--let $slave_sql_errno=1943
|
||||
--let $slave_sql_errno=1941
|
||||
--source include/wait_for_slave_sql_error.inc
|
||||
|
||||
--source include/stop_slave.inc
|
||||
ALTER TABLE mysql.rpl_slave_state ADD PRIMARY KEY (sub_id);
|
||||
START SLAVE;
|
||||
--let $slave_sql_errno=1943
|
||||
--let $slave_sql_errno=1941
|
||||
--source include/wait_for_slave_sql_error.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;
|
||||
|
||||
|
||||
--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
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t2;
|
||||
|
||||
--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)->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
|
||||
{
|
||||
|
@ -3958,6 +3938,30 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
|
|||
else
|
||||
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->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);
|
||||
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);
|
||||
thd->is_slave_error= 1;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
|
||||
const LEX_STRING rpl_gtid_slave_state_table_name=
|
||||
{ STRING_WITH_LEN("rpl_slave_state") };
|
||||
{ C_STRING_WITH_LEN("rpl_slave_state") };
|
||||
|
||||
|
||||
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);
|
||||
|
||||
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"),
|
||||
rpl_gtid_slave_state_table_name.str,
|
||||
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)
|
||||
{
|
||||
unlock();
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||
err= 1;
|
||||
goto end;
|
||||
}
|
||||
|
|
|
@ -1232,7 +1232,20 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos,
|
|||
else
|
||||
{
|
||||
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);
|
||||
/*
|
||||
Note that Rotate_log_event::do_apply_event() does not call this
|
||||
|
|
Loading…
Reference in a new issue