mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
MDEV-34049: Parallel access to temptable in different domain_id in parallel replication
Disallow changing @@gtid_domain_id while a temporary table is open in STATEMENT or MIXED binlog mode. Otherwise, a slave may try to replicate events refering to the same temporary table in parallel, using domain-based out-of-order parallel replication. This is not valid, temporary tables are only available for use within a single thread at a time. One concrete consequence seen from this bug was a ROLLBACK on an InnoDB temporary table running in one domain in parallel with DROP TEMPORARY TABLE in another domain, causing an assertion inside InnoDB: InnoDB: Failing assertion: table->get_ref_count() == 0 in dict_sys_t::remove. Use an existing error code that's somewhat close to the real issue (ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO), to not add a new error code in a GA release. When this is merged to the next GA release, we could optionally introduce a new and more precise error code for an attempt to change the domain_id while temporary tables are open. Reviewed-by: Brandon Nesterenko <brandon.nesterenko@mariadb.com> Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
This commit is contained in:
parent
0166c89e02
commit
d959acbbf8
3 changed files with 95 additions and 6 deletions
|
@ -60,6 +60,34 @@ ROLLBACK;
|
|||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
SET @old_mode= @@SESSION.binlog_format;
|
||||
SET SESSION binlog_format= row;
|
||||
SET SESSION gtid_domain_id= 200;
|
||||
CREATE TEMPORARY TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
SET SESSION gtid_domain_id= 0;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES (200);
|
||||
INSERT INTO t1 SELECT * FROM t2;
|
||||
COMMIT;
|
||||
SET SESSION gtid_domain_id= 201;
|
||||
SET SESSION gtid_domain_id= 0;
|
||||
DELETE FROM t1 WHERE a=200;
|
||||
SET SESSION gtid_domain_id= 202;
|
||||
DROP TEMPORARY TABLE t2;
|
||||
SET SESSION binlog_format= mixed;
|
||||
SET SESSION gtid_domain_id= 0;
|
||||
CREATE TEMPORARY TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES (1);
|
||||
SET SESSION gtid_domain_id= 0;
|
||||
SET SESSION gtid_domain_id= 204;
|
||||
ERROR HY000: Cannot modify @@session.gtid_domain_id or @@session.gtid_seq_no inside a transaction
|
||||
SET SESSION binlog_format=statement;
|
||||
INSERT INTO t2 VALUES (2);
|
||||
SET SESSION gtid_domain_id= 205;
|
||||
ERROR HY000: Cannot modify @@session.gtid_domain_id or @@session.gtid_seq_no inside a transaction
|
||||
DROP TEMPORARY TABLE t2;
|
||||
SET SESSION gtid_domain_id= @old_domain;
|
||||
SET SESSION binlog_format= @old_mode;
|
||||
*** Test requesting an explicit GTID position that conflicts with newer GTIDs of our own in the binlog. ***
|
||||
connection slave;
|
||||
include/stop_slave.inc
|
||||
|
@ -83,16 +111,16 @@ ERROR 25000: You are not allowed to execute this command in a transaction
|
|||
ROLLBACK;
|
||||
SET GLOBAL gtid_strict_mode= 1;
|
||||
SET GLOBAL gtid_slave_pos = "0-1-1";
|
||||
ERROR HY000: Specified GTID 0-1-1 conflicts with the binary log which contains a more recent GTID 0-2-11. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos
|
||||
ERROR HY000: Specified GTID 0-1-1 conflicts with the binary log which contains a more recent GTID 0-2-17. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos
|
||||
SET GLOBAL gtid_slave_pos = "";
|
||||
ERROR HY000: Specified value for @@gtid_slave_pos contains no value for replication domain 0. This conflicts with the binary log which contains GTID 0-2-11. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos
|
||||
ERROR HY000: Specified value for @@gtid_slave_pos contains no value for replication domain 0. This conflicts with the binary log which contains GTID 0-2-17. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos
|
||||
SET GLOBAL gtid_strict_mode= 0;
|
||||
SET GLOBAL gtid_slave_pos = "0-1-1";
|
||||
Warnings:
|
||||
Warning 1947 Specified GTID 0-1-1 conflicts with the binary log which contains a more recent GTID 0-2-11. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos
|
||||
Warning 1947 Specified GTID 0-1-1 conflicts with the binary log which contains a more recent GTID 0-2-17. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos
|
||||
SET GLOBAL gtid_slave_pos = "";
|
||||
Warnings:
|
||||
Warning 1948 Specified value for @@gtid_slave_pos contains no value for replication domain 0. This conflicts with the binary log which contains GTID 0-2-11. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos
|
||||
Warning 1948 Specified value for @@gtid_slave_pos contains no value for replication domain 0. This conflicts with the binary log which contains GTID 0-2-17. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos
|
||||
RESET MASTER;
|
||||
SET GLOBAL gtid_slave_pos = "0-1-1";
|
||||
START SLAVE;
|
||||
|
|
|
@ -68,6 +68,46 @@ SELECT * FROM t1 ORDER BY a;
|
|||
ROLLBACK;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
# MDEV-34049: Parallel access to temptable in different domain_id in parallel replication
|
||||
#
|
||||
# Temporary tables must be prevented from being accessed from multiple threads
|
||||
# at the same time in parallel replication. Withon one domain_id, this is done
|
||||
# by running wait_for_prior_commit() before accessing a temporary table. To
|
||||
# prevent the same temporary table from being accessed in parallel from two
|
||||
# domains in out-of-order parallel replication, an error must be raised on
|
||||
# attempt to change the gtid_domain_id while temporary tables are in use in
|
||||
# a session and binlogged. In row-based binlogging, temporary tables are not
|
||||
# binlogged, so gtid_domain_id can be freely changed.
|
||||
SET @old_mode= @@SESSION.binlog_format;
|
||||
SET SESSION binlog_format= row;
|
||||
SET SESSION gtid_domain_id= 200;
|
||||
CREATE TEMPORARY TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
SET SESSION gtid_domain_id= 0;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES (200);
|
||||
INSERT INTO t1 SELECT * FROM t2;
|
||||
COMMIT;
|
||||
SET SESSION gtid_domain_id= 201;
|
||||
SET SESSION gtid_domain_id= 0;
|
||||
DELETE FROM t1 WHERE a=200;
|
||||
SET SESSION gtid_domain_id= 202;
|
||||
DROP TEMPORARY TABLE t2;
|
||||
|
||||
SET SESSION binlog_format= mixed;
|
||||
SET SESSION gtid_domain_id= 0;
|
||||
CREATE TEMPORARY TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES (1);
|
||||
SET SESSION gtid_domain_id= 0;
|
||||
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO
|
||||
SET SESSION gtid_domain_id= 204;
|
||||
SET SESSION binlog_format=statement;
|
||||
INSERT INTO t2 VALUES (2);
|
||||
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO
|
||||
SET SESSION gtid_domain_id= 205;
|
||||
DROP TEMPORARY TABLE t2;
|
||||
SET SESSION gtid_domain_id= @old_domain;
|
||||
SET SESSION binlog_format= @old_mode;
|
||||
|
||||
|
||||
--echo *** Test requesting an explicit GTID position that conflicts with newer GTIDs of our own in the binlog. ***
|
||||
--connection slave
|
||||
|
|
|
@ -1806,12 +1806,33 @@ Sys_pseudo_thread_id(
|
|||
static bool
|
||||
check_gtid_domain_id(sys_var *self, THD *thd, set_var *var)
|
||||
{
|
||||
if (var->type != OPT_GLOBAL &&
|
||||
error_if_in_trans_or_substatement(thd,
|
||||
if (var->type != OPT_GLOBAL)
|
||||
{
|
||||
if (error_if_in_trans_or_substatement(thd,
|
||||
ER_STORED_FUNCTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO,
|
||||
ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO))
|
||||
return true;
|
||||
/*
|
||||
All binlogged statements on a temporary table must be binlogged in the
|
||||
same domain_id; it is not safe to run them in parallel in different
|
||||
domains, temporary table must be exclusive to a single thread.
|
||||
In row-based binlogging, temporary tables do not end up in the binlog,
|
||||
so there is no such issue.
|
||||
|
||||
ToDo: When merging to next (non-GA) release, introduce a more specific
|
||||
error that describes that the problem is changing gtid_domain_id with
|
||||
open temporary tables in statement/mixed binlogging mode; it is not
|
||||
really due to doing it inside a "transaction".
|
||||
*/
|
||||
if (thd->has_thd_temporary_tables() &&
|
||||
!thd->is_current_stmt_binlog_format_row() &&
|
||||
var->save_result.ulonglong_value != thd->variables.gtid_domain_id)
|
||||
{
|
||||
my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO,
|
||||
MYF(0));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue