Commit 1d474979 authored by unknown's avatar unknown

MDEV-4478: Implement GTID "strict mode"

When @@GLOBAL.gtid_strict_mode=1, then certain operations result
in error that would otherwise result in out-of-order binlog files
between servers.

GTID sequence numbers are now allocated independently per domain;
this results in less/no holes in GTID sequences, increasing the
likelyhood that diverging binlogs will be caught by the slave when
GTID strict mode is enabled.
parent 3c4dbdcf
...@@ -207,6 +207,10 @@ The following options may be given as the first argument: ...@@ -207,6 +207,10 @@ The following options may be given as the first argument:
multiple masters), each independent source server must multiple masters), each independent source server must
use a distinct domain_id. For simple tree-shaped use a distinct domain_id. For simple tree-shaped
replication topologies, it can be left at its default, 0. replication topologies, it can be left at its default, 0.
--gtid-strict-mode Enforce strict seq_no ordering of events in the binary
log. Slave stops with an error if it encounters an event
that would cause it to generate an out-of-order binlog if
executed.
-?, --help Display this help and exit. -?, --help Display this help and exit.
--histogram-size=# Number of bytes used for a histogram. If set to 0, no --histogram-size=# Number of bytes used for a histogram. If set to 0, no
histograms are created by ANALYZE. histograms are created by ANALYZE.
...@@ -966,6 +970,7 @@ gdb FALSE ...@@ -966,6 +970,7 @@ gdb FALSE
general-log FALSE general-log FALSE
group-concat-max-len 1024 group-concat-max-len 1024
gtid-domain-id 0 gtid-domain-id 0
gtid-strict-mode FALSE
help TRUE help TRUE
histogram-size 0 histogram-size 0
histogram-type SINGLE_PREC_HB histogram-type SINGLE_PREC_HB
......
...@@ -55,7 +55,6 @@ wait/synch/mutex/sql/LOCK_global_index_stats ...@@ -55,7 +55,6 @@ wait/synch/mutex/sql/LOCK_global_index_stats
wait/synch/mutex/sql/LOCK_global_system_variables wait/synch/mutex/sql/LOCK_global_system_variables
wait/synch/mutex/sql/LOCK_global_table_stats wait/synch/mutex/sql/LOCK_global_table_stats
wait/synch/mutex/sql/LOCK_global_user_client_stats wait/synch/mutex/sql/LOCK_global_user_client_stats
wait/synch/mutex/sql/LOCK_gtid_counter
wait/synch/mutex/sql/LOCK_open wait/synch/mutex/sql/LOCK_open
wait/synch/mutex/sql/LOCK_plugin wait/synch/mutex/sql/LOCK_plugin
wait/synch/mutex/sql/LOCK_prepared_stmt_count wait/synch/mutex/sql/LOCK_prepared_stmt_count
......
...@@ -41,7 +41,7 @@ master-bin.000002 # ...@@ -41,7 +41,7 @@ master-bin.000002 #
master-bin.000003 # master-bin.000003 #
SHOW BINLOG EVENTS IN 'master-bin.000003' LIMIT 1,1; SHOW BINLOG EVENTS IN 'master-bin.000003' LIMIT 1,1;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000003 # Gtid_list # # [1-1-3,2-1-4,0-1-1] master-bin.000003 # Gtid_list # # [1-1-2,2-1-1,0-1-1]
SET SESSION debug_dbug="+d,crash_dispatch_command_before"; SET SESSION debug_dbug="+d,crash_dispatch_command_before";
SELECT 1; SELECT 1;
Got one of the listed errors Got one of the listed errors
...@@ -53,7 +53,7 @@ master-bin.000003 # ...@@ -53,7 +53,7 @@ master-bin.000003 #
master-bin.000004 # master-bin.000004 #
SHOW BINLOG EVENTS IN 'master-bin.000004' LIMIT 1,1; SHOW BINLOG EVENTS IN 'master-bin.000004' LIMIT 1,1;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000004 # Gtid_list # # [1-1-3,0-1-1,2-1-4] master-bin.000004 # Gtid_list # # [1-1-2,0-1-1,2-1-1]
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a a
1 1
......
...@@ -46,6 +46,12 @@ INSERT INTO t1 VALUES (100); ...@@ -46,6 +46,12 @@ INSERT INTO t1 VALUES (100);
SET GLOBAL gtid_slave_pos = "100-100-100"; SET GLOBAL gtid_slave_pos = "100-100-100";
ERROR 25000: You are not allowed to execute this command in a transaction ERROR 25000: You are not allowed to execute this command in a transaction
ROLLBACK; 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.
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.
SET GLOBAL gtid_strict_mode= 0;
SET GLOBAL gtid_slave_pos = "0-1-1"; SET GLOBAL gtid_slave_pos = "0-1-1";
Warnings: 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-11. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos.
......
...@@ -41,10 +41,10 @@ INSERT INTO t4 VALUES (3, 1); ...@@ -41,10 +41,10 @@ INSERT INTO t4 VALUES (3, 1);
INSERT INTO t3 VALUES (3); INSERT INTO t3 VALUES (3);
INSERT INTO t3 VALUES (4); INSERT INTO t3 VALUES (4);
INSERT INTO t4 VALUES (3, 3); INSERT INTO t4 VALUES (3, 3);
START SLAVE UNTIL master_gtid_pos= "1-1-7,2-1-14,3-1-21"; START SLAVE UNTIL master_gtid_pos= "1-1-4,2-1-4,3-1-4";
START SLAVE UNTIL master_gtid_pos= "1-1-4,2-1-14,3-1-24"; START SLAVE UNTIL master_gtid_pos= "1-1-1,2-1-4,3-1-7";
START SLAVE UNTIL master_gtid_pos= "2-1-11,3-1-21,1-1-10"; START SLAVE UNTIL master_gtid_pos= "2-1-1,3-1-4,1-1-7";
START SLAVE UNTIL master_gtid_pos= "3-1-18,1-1-7,2-1-17"; START SLAVE UNTIL master_gtid_pos= "3-1-1,1-1-4,2-1-7";
include/wait_for_slave_to_stop.inc include/wait_for_slave_to_stop.inc
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a a
...@@ -119,7 +119,7 @@ a b ...@@ -119,7 +119,7 @@ a b
2 3 2 3
*** Now replicate all extra changes from 3,4,5 to 2, in preparation for making 2 the new master. *** *** Now replicate all extra changes from 3,4,5 to 2, in preparation for making 2 the new master. ***
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_3; CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_3;
START SLAVE UNTIL master_gtid_pos = "1-1-4,0-1-3,3-1-24,2-1-14"; START SLAVE UNTIL master_gtid_pos = "1-1-1,0-1-3,3-1-7,2-1-4";
include/wait_for_slave_to_stop.inc include/wait_for_slave_to_stop.inc
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a a
...@@ -142,7 +142,7 @@ a b ...@@ -142,7 +142,7 @@ a b
3 1 3 1
3 3 3 3
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_4; CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_4;
START SLAVE UNTIL master_gtid_pos = "1-1-10,0-1-3,3-1-21,2-1-11"; START SLAVE UNTIL master_gtid_pos = "1-1-7,0-1-3,3-1-4,2-1-1";
include/wait_for_slave_to_stop.inc include/wait_for_slave_to_stop.inc
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a a
...@@ -168,7 +168,7 @@ a b ...@@ -168,7 +168,7 @@ a b
3 1 3 1
3 3 3 3
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_5; CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_5;
START SLAVE UNTIL master_gtid_pos = "1-1-7,0-1-3,3-1-18,2-1-17"; START SLAVE UNTIL master_gtid_pos = "1-1-4,0-1-3,3-1-1,2-1-7";
include/wait_for_slave_to_stop.inc include/wait_for_slave_to_stop.inc
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a a
......
...@@ -32,10 +32,10 @@ master-bin.000003 # Gtid_list # # [0-1-3] ...@@ -32,10 +32,10 @@ master-bin.000003 # Gtid_list # # [0-1-3]
FLUSH LOGS; FLUSH LOGS;
SHOW BINLOG EVENTS IN 'master-bin.000004' LIMIT 1,1; SHOW BINLOG EVENTS IN 'master-bin.000004' LIMIT 1,1;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000004 # Gtid_list # # [1-1-5,0-1-4] master-bin.000004 # Gtid_list # # [1-1-1,0-1-4]
SHOW BINLOG EVENTS IN 'master-bin.000005' LIMIT 1,1; SHOW BINLOG EVENTS IN 'master-bin.000005' LIMIT 1,1;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000005 # Gtid_list # # [1-1-5,0-1-4] master-bin.000005 # Gtid_list # # [1-1-1,0-1-4]
show binary logs; show binary logs;
Log_name File_size Log_name File_size
master-bin.000002 # master-bin.000002 #
......
include/rpl_init.inc [topology=1->2]
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
SET sql_log_bin= 0;
call mtr.add_suppression("Error writing file .*errno: 1950");
SET sql_log_bin= 1;
SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode;
SET GLOBAL gtid_strict_mode= 1;
include/stop_slave.inc
SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode;
SET GLOBAL gtid_strict_mode=1;
CHANGE MASTER TO master_use_gtid=slave_pos;
include/start_slave.inc
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1)
master-bin.000001 # Xid # # COMMIT /* XID */
SET server_id= 3;
SET gtid_seq_no= 3;
ERROR HY000: An attempt was made to binlog GTID 0-3-3 which would create an out-of-order sequence number with existing GTID 0-1-3, and gtid strict mode is enabled.
SET SESSION debug_dbug="+d,ignore_set_gtid_seq_no_check";
SET gtid_seq_no= 3;
SET SESSION debug_dbug="-d,ignore_set_gtid_seq_no_check";
INSERT INTO t1 VALUES (2);
ERROR HY000: An attempt was made to binlog GTID 0-3-3 which would create an out-of-order sequence number with existing GTID 0-1-3, and gtid strict mode is enabled.
SET gtid_seq_no= 2;
ERROR HY000: An attempt was made to binlog GTID 0-3-2 which would create an out-of-order sequence number with existing GTID 0-1-3, and gtid strict mode is enabled.
SET SESSION debug_dbug="+d,ignore_set_gtid_seq_no_check";
SET gtid_seq_no= 2;
SET SESSION debug_dbug="-d,ignore_set_gtid_seq_no_check";
INSERT INTO t1 VALUES (3);
ERROR HY000: An attempt was made to binlog GTID 0-3-2 which would create an out-of-order sequence number with existing GTID 0-1-3, and gtid strict mode is enabled.
SET server_id= 1;
SET gtid_seq_no= 4;
INSERT INTO t1 VALUES (4);
SELECT * FROM t1 ORDER BY 1;
a
1
4
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4)
master-bin.000001 # Xid # # COMMIT /* XID */
*** Test non-transactional GTID error (cannot be rolled back). ***
SET server_id= 3;
SET gtid_seq_no= 1;
ERROR HY000: An attempt was made to binlog GTID 0-3-1 which would create an out-of-order sequence number with existing GTID 0-1-4, and gtid strict mode is enabled.
SET SESSION debug_dbug="+d,ignore_set_gtid_seq_no_check";
SET gtid_seq_no= 1;
SET SESSION debug_dbug="-d,ignore_set_gtid_seq_no_check";
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=MyISAM;
ERROR HY000: An attempt was made to binlog GTID 0-3-1 which would create an out-of-order sequence number with existing GTID 0-1-4, and gtid strict mode is enabled.
SET sql_log_bin= 0;
DROP TABLE t2;
SET sql_log_bin= 1;
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=MyISAM;
SET gtid_seq_no= 1;
ERROR HY000: An attempt was made to binlog GTID 0-3-1 which would create an out-of-order sequence number with existing GTID 0-3-5, and gtid strict mode is enabled.
SET SESSION debug_dbug="+d,ignore_set_gtid_seq_no_check";
SET gtid_seq_no= 1;
SET SESSION debug_dbug="-d,ignore_set_gtid_seq_no_check";
INSERT INTO t2 VALUES (1);
ERROR HY000: An attempt was made to binlog GTID 0-3-1 which would create an out-of-order sequence number with existing GTID 0-3-5, and gtid strict mode is enabled.
SET server_id= 1;
SET gtid_seq_no= 6;
INSERT INTO t2 VALUES (2);
SELECT * FROM t2 ORDER BY a;
a
1
2
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=MyISAM
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t2 VALUES (2)
master-bin.000001 # Query # # COMMIT
*** Test that slave stops if it tries to apply a GTID that would create out-of-order binlog GTID sequence numbers. ***
SELECT * FROM t1 ORDER BY a;
a
1
4
SELECT * FROM t2 ORDER BY a;
a
2
SET sql_log_bin= 0;
call mtr.add_suppression("An attempt was made to binlog GTID .* which would create an out-of-order sequence number with existing GTID .*, and gtid strict mode is enabled");
call mtr.add_suppression("The binlog on the master is missing the GTID [-0-9]+ requested by the slave");
SET sql_log_bin= 1;
INSERT INTO t1 VALUES (5);
INSERT INTO t1 VALUES (6);
include/wait_for_slave_sql_error.inc [errno=1950]
STOP SLAVE IO_THREAD;
SET GLOBAL gtid_strict_mode=0;
include/start_slave.inc
SET GLOBAL gtid_strict_mode=1;
SELECT * FROM t1 ORDER BY a;
a
1
4
5
6
INSERT INTO t1 VALUES (7);
CREATE TABLE t3 (a INT PRIMARY KEY);
include/wait_for_slave_sql_error.inc [errno=1950]
SHOW CREATE TABLE t3;
ERROR 42S02: Table 'test.t3' doesn't exist
STOP SLAVE IO_THREAD;
SET GLOBAL gtid_strict_mode=0;
include/start_slave.inc
SET GLOBAL gtid_strict_mode=1;
SHOW CREATE TABLE t3;
Table t3
Create Table CREATE TABLE `t3` (
`a` int(11) NOT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES (8);
INSERT INTO t2 VALUES (3);
include/wait_for_slave_sql_error.inc [errno=1950]
SELECT * FROM t2 ORDER BY a;
a
2
STOP SLAVE IO_THREAD;
SET GLOBAL gtid_strict_mode=0;
include/start_slave.inc
SET GLOBAL gtid_strict_mode=1;
SELECT * FROM t2 ORDER BY a;
a
2
3
*** Check slave requests starting from a hole on the master. ***
include/stop_slave.inc
INSERT INTO t1 VALUES (10);
SET gtid_seq_no= 100;
INSERT INTO t1 VALUES (11);
INSERT INTO t1 VALUES (12);
SET GLOBAL gtid_slave_pos= "0-1-50";
START SLAVE;
include/wait_for_slave_io_error.inc [errno=1236]
STOP SLAVE SQL_THREAD;
SET GLOBAL gtid_strict_mode= 0;
include/start_slave.inc
SELECT * FROM t1 ORDER BY a;
a
1
4
5
6
7
8
11
12
SET GLOBAL gtid_strict_mode= 1;
DROP TABLE t1, t2, t3;
SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
include/rpl_end.inc
...@@ -79,7 +79,7 @@ master-bin.000001 # ...@@ -79,7 +79,7 @@ master-bin.000001 #
master-bin.000002 # master-bin.000002 #
master-bin.000003 # master-bin.000003 #
master-bin.000004 # master-bin.000004 #
START SLAVE UNTIL master_gtid_pos='1-1-11,2-1-12'; START SLAVE UNTIL master_gtid_pos='1-1-3,2-1-4';
include/wait_for_slave_to_stop.inc include/wait_for_slave_to_stop.inc
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a a
...@@ -93,7 +93,7 @@ a ...@@ -93,7 +93,7 @@ a
3 3
4 4
5 5
START SLAVE UNTIL master_gtid_pos='1-1-13,2-1-8'; START SLAVE UNTIL master_gtid_pos='1-1-4,2-1-2';
include/wait_for_slave_to_stop.inc include/wait_for_slave_to_stop.inc
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a a
...@@ -108,7 +108,7 @@ a ...@@ -108,7 +108,7 @@ a
3 3
4 4
5 5
START SLAVE UNTIL master_gtid_pos='1-1-11'; START SLAVE UNTIL master_gtid_pos='1-1-3';
include/wait_for_slave_to_stop.inc include/wait_for_slave_to_stop.inc
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a a
...@@ -144,7 +144,7 @@ FLUSH LOGS; ...@@ -144,7 +144,7 @@ FLUSH LOGS;
SET gtid_domain_id = 1; SET gtid_domain_id = 1;
INSERT INTO t1 VALUES (7); INSERT INTO t1 VALUES (7);
SET gtid_domain_id = 0; SET gtid_domain_id = 0;
START SLAVE UNTIL master_gtid_pos='1-1-13'; START SLAVE UNTIL master_gtid_pos='1-1-4';
include/wait_for_slave_to_stop.inc include/wait_for_slave_to_stop.inc
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a a
...@@ -168,7 +168,7 @@ a ...@@ -168,7 +168,7 @@ a
include/stop_slave.inc include/stop_slave.inc
CREATE TABLE t3 (a INT); CREATE TABLE t3 (a INT);
DROP TABLE t3; DROP TABLE t3;
START SLAVE UNTIL master_gtid_pos='1-1-15,2-1-14,0-1-16'; START SLAVE UNTIL master_gtid_pos='1-1-5,2-1-5,0-1-6';
include/wait_for_slave_to_stop.inc include/wait_for_slave_to_stop.inc
SHOW CREATE TABLE t3; SHOW CREATE TABLE t3;
Table Create Table Table Create Table
......
...@@ -80,7 +80,13 @@ SET GLOBAL gtid_slave_pos = "100-100-100"; ...@@ -80,7 +80,13 @@ SET GLOBAL gtid_slave_pos = "100-100-100";
ROLLBACK; ROLLBACK;
# In gtid non-strict mode, we get warnings for setting @@gtid_slave_pos back # In gtid non-strict mode, we get warnings for setting @@gtid_slave_pos back
# to earlier than what is in the binlog. # to earlier than what is in the binlog. In strict mode, we get an error.
SET GLOBAL gtid_strict_mode= 1;
--error ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG
SET GLOBAL gtid_slave_pos = "0-1-1";
--error ER_MASTER_GTID_POS_MISSING_DOMAIN
SET GLOBAL gtid_slave_pos = "";
SET GLOBAL gtid_strict_mode= 0;
SET GLOBAL gtid_slave_pos = "0-1-1"; SET GLOBAL gtid_slave_pos = "0-1-1";
SET GLOBAL gtid_slave_pos = ""; SET GLOBAL gtid_slave_pos = "";
RESET MASTER; RESET MASTER;
......
--source include/have_debug.inc
--source include/have_innodb.inc
--source include/have_binlog_format_statement.inc
--let $rpl_topology=1->2
--source include/rpl_init.inc
--connection server_1
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
SET sql_log_bin= 0;
call mtr.add_suppression("Error writing file .*errno: 1950");
SET sql_log_bin= 1;
SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode;
SET GLOBAL gtid_strict_mode= 1;
--connection server_2
--source include/stop_slave.inc
SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode;
SET GLOBAL gtid_strict_mode=1;
CHANGE MASTER TO master_use_gtid=slave_pos;
--source include/start_slave.inc
--connection server_1
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
--source include/show_binlog_events.inc
SET server_id= 3;
--error ER_GTID_STRICT_OUT_OF_ORDER
SET gtid_seq_no= 3;
SET SESSION debug_dbug="+d,ignore_set_gtid_seq_no_check";
SET gtid_seq_no= 3;
SET SESSION debug_dbug="-d,ignore_set_gtid_seq_no_check";
--error ER_GTID_STRICT_OUT_OF_ORDER
INSERT INTO t1 VALUES (2);
--error ER_GTID_STRICT_OUT_OF_ORDER
SET gtid_seq_no= 2;
SET SESSION debug_dbug="+d,ignore_set_gtid_seq_no_check";
SET gtid_seq_no= 2;
SET SESSION debug_dbug="-d,ignore_set_gtid_seq_no_check";
--error ER_GTID_STRICT_OUT_OF_ORDER
INSERT INTO t1 VALUES (3);
SET server_id= 1;
SET gtid_seq_no= 4;
INSERT INTO t1 VALUES (4);
SELECT * FROM t1 ORDER BY 1;
--source include/show_binlog_events.inc
--echo *** Test non-transactional GTID error (cannot be rolled back). ***
SET server_id= 3;
--error ER_GTID_STRICT_OUT_OF_ORDER
SET gtid_seq_no= 1;
SET SESSION debug_dbug="+d,ignore_set_gtid_seq_no_check";
SET gtid_seq_no= 1;
SET SESSION debug_dbug="-d,ignore_set_gtid_seq_no_check";
--error ER_GTID_STRICT_OUT_OF_ORDER
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=MyISAM;
# The table is still created, DDL cannot be rolled back.
# Fix it up for replication.
SET sql_log_bin= 0;
DROP TABLE t2;
SET sql_log_bin= 1;
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=MyISAM;
--error ER_GTID_STRICT_OUT_OF_ORDER
SET gtid_seq_no= 1;
SET SESSION debug_dbug="+d,ignore_set_gtid_seq_no_check";
SET gtid_seq_no= 1;
SET SESSION debug_dbug="-d,ignore_set_gtid_seq_no_check";
--error ER_GTID_STRICT_OUT_OF_ORDER
INSERT INTO t2 VALUES (1);
# The value is still inserted, cannot be rolled back.
SET server_id= 1;
SET gtid_seq_no= 6;
INSERT INTO t2 VALUES (2);
SELECT * FROM t2 ORDER BY a;
--source include/show_binlog_events.inc
--echo *** Test that slave stops if it tries to apply a GTID that would create out-of-order binlog GTID sequence numbers. ***
--save_master_pos
--connection server_2
--sync_with_master
SELECT * FROM t1 ORDER BY a;
SELECT * FROM t2 ORDER BY a;
SET sql_log_bin= 0;
call mtr.add_suppression("An attempt was made to binlog GTID .* which would create an out-of-order sequence number with existing GTID .*, and gtid strict mode is enabled");
call mtr.add_suppression("The binlog on the master is missing the GTID [-0-9]+ requested by the slave");
SET sql_log_bin= 1;
# Create some out-of-order stuff on slave.
INSERT INTO t1 VALUES (5);
--connection server_1
INSERT INTO t1 VALUES (6);
--save_master_pos
--connection server_2
--let $slave_sql_errno=1950
--source include/wait_for_slave_sql_error.inc
STOP SLAVE IO_THREAD;
SET GLOBAL gtid_strict_mode=0;
--source include/start_slave.inc
--sync_with_master
SET GLOBAL gtid_strict_mode=1;
SELECT * FROM t1 ORDER BY a;
INSERT INTO t1 VALUES (7);
--connection server_1
CREATE TABLE t3 (a INT PRIMARY KEY);
--save_master_pos
--connection server_2
--let $slave_sql_errno=1950
--source include/wait_for_slave_sql_error.inc
--error ER_NO_SUCH_TABLE
--query_vertical SHOW CREATE TABLE t3
STOP SLAVE IO_THREAD;
SET GLOBAL gtid_strict_mode=0;
--source include/start_slave.inc
--sync_with_master
SET GLOBAL gtid_strict_mode=1;
--query_vertical SHOW CREATE TABLE t3
INSERT INTO t1 VALUES (8);
--connection server_1
INSERT INTO t2 VALUES (3);
--save_master_pos
--connection server_2
--let $slave_sql_errno=1950
--source include/wait_for_slave_sql_error.inc
SELECT * FROM t2 ORDER BY a;
STOP SLAVE IO_THREAD;
SET GLOBAL gtid_strict_mode=0;
--source include/start_slave.inc
--sync_with_master
SET GLOBAL gtid_strict_mode=1;
SELECT * FROM t2 ORDER BY a;
--echo *** Check slave requests starting from a hole on the master. ***
--connection server_2
--source include/stop_slave.inc
--connection server_1
INSERT INTO t1 VALUES (10);
SET gtid_seq_no= 100;
INSERT INTO t1 VALUES (11);
INSERT INTO t1 VALUES (12);
--save_master_pos
--connection server_2
SET GLOBAL gtid_slave_pos= "0-1-50";
START SLAVE;
--let $slave_io_errno=1236
--source include/wait_for_slave_io_error.inc
STOP SLAVE SQL_THREAD;
SET GLOBAL gtid_strict_mode= 0;
--source include/start_slave.inc
--sync_with_master
SELECT * FROM t1 ORDER BY a;
SET GLOBAL gtid_strict_mode= 1;
# Clean up.
--connection server_1
DROP TABLE t1, t2, t3;
SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
--connection server_2
SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
--source include/rpl_end.inc
select @@global.gtid_strict_mode;
@@global.gtid_strict_mode
0
select @@session.gtid_strict_mode;
ERROR HY000: Variable 'gtid_strict_mode' is a GLOBAL variable
show global variables like 'gtid_strict_mode';
Variable_name Value
gtid_strict_mode OFF
show session variables like 'gtid_strict_mode';
Variable_name Value
gtid_strict_mode OFF
select * from information_schema.global_variables where variable_name='gtid_strict_mode';
VARIABLE_NAME VARIABLE_VALUE
GTID_STRICT_MODE OFF
select * from information_schema.session_variables where variable_name='gtid_strict_mode';
VARIABLE_NAME VARIABLE_VALUE
GTID_STRICT_MODE OFF
SET @old= @@GLOBAL.gtid_strict_mode;
set global gtid_strict_mode=1;
select @@global.gtid_strict_mode;
@@global.gtid_strict_mode
1
set global gtid_strict_mode=0;
select @@global.gtid_strict_mode;
@@global.gtid_strict_mode
0
set global gtid_strict_mode=@old;
set session gtid_strict_mode=1;
ERROR HY000: Variable 'gtid_strict_mode' is a GLOBAL variable and should be set with SET GLOBAL
--source include/not_embedded.inc
#
# only global
#
select @@global.gtid_strict_mode;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.gtid_strict_mode;
show global variables like 'gtid_strict_mode';
show session variables like 'gtid_strict_mode';
select * from information_schema.global_variables where variable_name='gtid_strict_mode';
select * from information_schema.session_variables where variable_name='gtid_strict_mode';
SET @old= @@GLOBAL.gtid_strict_mode;
set global gtid_strict_mode=1;
select @@global.gtid_strict_mode;
set global gtid_strict_mode=0;
select @@global.gtid_strict_mode;
set global gtid_strict_mode=@old;
--error ER_GLOBAL_VARIABLE
set session gtid_strict_mode=1;
...@@ -3841,9 +3841,6 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log) ...@@ -3841,9 +3841,6 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log)
if (!is_relay_log) if (!is_relay_log)
{ {
rpl_global_gtid_binlog_state.reset(); rpl_global_gtid_binlog_state.reset();
mysql_mutex_lock(&LOCK_gtid_counter);
global_gtid_counter= 0;
mysql_mutex_unlock(&LOCK_gtid_counter);
} }
/* Start logging with a new file */ /* Start logging with a new file */
...@@ -5367,9 +5364,11 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone, ...@@ -5367,9 +5364,11 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone,
bool is_transactional) bool is_transactional)
{ {
rpl_gtid gtid; rpl_gtid gtid;
uint64 seq_no; uint32 domain_id= thd->variables.gtid_domain_id;
uint32 server_id= thd->variables.server_id;
uint64 seq_no= thd->variables.gtid_seq_no;
int err;
seq_no= thd->variables.gtid_seq_no;
/* /*
Reset the session variable gtid_seq_no, to reduce the risk of accidentally Reset the session variable gtid_seq_no, to reduce the risk of accidentally
producing a duplicate GTID. producing a duplicate GTID.
...@@ -5377,34 +5376,36 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone, ...@@ -5377,34 +5376,36 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone,
thd->variables.gtid_seq_no= 0; thd->variables.gtid_seq_no= 0;
if (seq_no != 0) if (seq_no != 0)
{ {
/* /* Use the specified sequence number. */
If we see a higher sequence number, use that one as the basis of any gtid.domain_id= domain_id;
later generated sequence numbers. gtid.server_id= server_id;
*/ gtid.seq_no= seq_no;
bump_seq_no_counter_if_needed(seq_no); mysql_mutex_lock(&LOCK_rpl_gtid_state);
err= rpl_global_gtid_binlog_state.update(&gtid, opt_gtid_strict_mode);
mysql_mutex_unlock(&LOCK_rpl_gtid_state);
if (err && thd->stmt_da->sql_errno()==ER_GTID_STRICT_OUT_OF_ORDER)
errno= ER_GTID_STRICT_OUT_OF_ORDER;
} }
else else
{ {
mysql_mutex_lock(&LOCK_gtid_counter); /* Allocate the next sequence number for the GTID. */
seq_no= ++global_gtid_counter; mysql_mutex_lock(&LOCK_rpl_gtid_state);
mysql_mutex_unlock(&LOCK_gtid_counter); err= rpl_global_gtid_binlog_state.update_with_next_gtid(domain_id,
server_id, &gtid);
mysql_mutex_unlock(&LOCK_rpl_gtid_state);
seq_no= gtid.seq_no;
} }
gtid.seq_no= seq_no; if (err)
gtid.domain_id= thd->variables.gtid_domain_id; return true;
Gtid_log_event gtid_event(thd, gtid.seq_no, gtid.domain_id, standalone, Gtid_log_event gtid_event(thd, seq_no, domain_id, standalone,
LOG_EVENT_SUPPRESS_USE_F, is_transactional); LOG_EVENT_SUPPRESS_USE_F, is_transactional);
gtid.server_id= gtid_event.server_id;
/* Write the event to the binary log. */ /* Write the event to the binary log. */
if (gtid_event.write(&mysql_bin_log.log_file)) if (gtid_event.write(&mysql_bin_log.log_file))
return true; return true;
status_var_add(thd->status_var.binlog_bytes_written, gtid_event.data_written); status_var_add(thd->status_var.binlog_bytes_written, gtid_event.data_written);
/* Update the replication state (last GTID in each replication domain). */
mysql_mutex_lock(&LOCK_rpl_gtid_state);
rpl_global_gtid_binlog_state.update(&gtid);
mysql_mutex_unlock(&LOCK_rpl_gtid_state);
return false; return false;
} }
...@@ -5505,9 +5506,6 @@ MYSQL_BIN_LOG::read_state_from_file() ...@@ -5505,9 +5506,6 @@ MYSQL_BIN_LOG::read_state_from_file()
end_io_cache(&cache); end_io_cache(&cache);
if (opened) if (opened)
mysql_file_close(file_no, MYF(0)); mysql_file_close(file_no, MYF(0));
/* Pick the next unused seq_no from the loaded binlog state. */
bump_seq_no_counter_if_needed(
rpl_global_gtid_binlog_state.seq_no_from_state());
return err; return err;
} }
...@@ -5549,33 +5547,44 @@ bool ...@@ -5549,33 +5547,44 @@ bool
MYSQL_BIN_LOG::lookup_domain_in_binlog_state(uint32 domain_id, MYSQL_BIN_LOG::lookup_domain_in_binlog_state(uint32 domain_id,
rpl_gtid *out_gtid) rpl_gtid *out_gtid)
{ {
rpl_binlog_state::element *elem; rpl_gtid *found_gtid;
bool res; bool res= false;
mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state); mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
elem= (rpl_binlog_state::element *) if ((found_gtid= rpl_global_gtid_binlog_state.find_most_recent(domain_id)))
my_hash_search(&rpl_global_gtid_binlog_state.hash,
(const uchar *)&domain_id, 0);
if (elem)
{ {
*out_gtid= *found_gtid;
res= true; res= true;
*out_gtid= *elem->last_gtid;
} }
else
res= false;
mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state); mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
return res; return res;
} }
void int
MYSQL_BIN_LOG::bump_seq_no_counter_if_needed(uint64 seq_no) MYSQL_BIN_LOG::bump_seq_no_counter_if_needed(uint32 domain_id, uint64 seq_no)
{
int err;
mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
err= rpl_global_gtid_binlog_state.bump_seq_no_if_needed(domain_id, seq_no);
mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
return err;
}
bool
MYSQL_BIN_LOG::check_strict_gtid_sequence(uint32 domain_id, uint32 server_id,
uint64 seq_no)
{ {
mysql_mutex_lock(&LOCK_gtid_counter); bool err;
if (global_gtid_counter < seq_no)
global_gtid_counter= seq_no; mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
mysql_mutex_unlock(&LOCK_gtid_counter); err= rpl_global_gtid_binlog_state.check_strict_sequence(domain_id, server_id,
seq_no);
mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
return err;
} }
...@@ -5648,7 +5657,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) ...@@ -5648,7 +5657,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
my_org_b_tell= my_b_tell(file); my_org_b_tell= my_b_tell(file);
mysql_mutex_lock(&LOCK_log); mysql_mutex_lock(&LOCK_log);
prev_binlog_id= current_binlog_id; prev_binlog_id= current_binlog_id;
write_gtid_event(thd, true, using_trans); if (write_gtid_event(thd, true, using_trans))
goto err;
} }
else else
{ {
...@@ -6717,8 +6727,8 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) ...@@ -6717,8 +6727,8 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
*/ */
DBUG_ASSERT(!cache_mngr->stmt_cache.empty() || !cache_mngr->trx_cache.empty()); DBUG_ASSERT(!cache_mngr->stmt_cache.empty() || !cache_mngr->trx_cache.empty());
current->error= write_transaction_or_stmt(current); if ((current->error= write_transaction_or_stmt(current)))
current->commit_errno= errno;
strmake(cache_mngr->last_commit_pos_file, log_file_name, strmake(cache_mngr->last_commit_pos_file, log_file_name,
sizeof(cache_mngr->last_commit_pos_file)-1); sizeof(cache_mngr->last_commit_pos_file)-1);
commit_offset= my_b_write_tell(&log_file); commit_offset= my_b_write_tell(&log_file);
...@@ -8264,9 +8274,6 @@ int TC_LOG_BINLOG::open(const char *opt_name) ...@@ -8264,9 +8274,6 @@ int TC_LOG_BINLOG::open(const char *opt_name)
error= recover(&log_info, log_name, &log, error= recover(&log_info, log_name, &log,
(Format_description_log_event *)ev); (Format_description_log_event *)ev);
state_read= true; state_read= true;
/* Pick the next unused seq_no from the recovered binlog state. */
bump_seq_no_counter_if_needed(
rpl_global_gtid_binlog_state.seq_no_from_state());
} }
else else
error= read_state_from_file(); error= read_state_from_file();
...@@ -8748,7 +8755,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name, ...@@ -8748,7 +8755,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
gtid.domain_id= gev->domain_id; gtid.domain_id= gev->domain_id;
gtid.server_id= gev->server_id; gtid.server_id= gev->server_id;
gtid.seq_no= gev->seq_no; gtid.seq_no= gev->seq_no;
if (rpl_global_gtid_binlog_state.update(&gtid)) if (rpl_global_gtid_binlog_state.update(&gtid, false))
goto err2; goto err2;
} }
break; break;
......
...@@ -783,7 +783,9 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG ...@@ -783,7 +783,9 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
bool find_in_binlog_state(uint32 domain_id, uint32 server_id, bool find_in_binlog_state(uint32 domain_id, uint32 server_id,
rpl_gtid *out_gtid); rpl_gtid *out_gtid);
bool lookup_domain_in_binlog_state(uint32 domain_id, rpl_gtid *out_gtid); bool lookup_domain_in_binlog_state(uint32 domain_id, rpl_gtid *out_gtid);
void bump_seq_no_counter_if_needed(uint64 seq_no); int bump_seq_no_counter_if_needed(uint32 domain_id, uint64 seq_no);
bool check_strict_gtid_sequence(uint32 domain_id, uint32 server_id,
uint64 seq_no);
}; };
class Log_event_handler class Log_event_handler
......
...@@ -6214,6 +6214,15 @@ Gtid_log_event::do_apply_event(Relay_log_info const *rli) ...@@ -6214,6 +6214,15 @@ Gtid_log_event::do_apply_event(Relay_log_info const *rli)
thd->variables.gtid_domain_id= this->domain_id; thd->variables.gtid_domain_id= this->domain_id;
thd->variables.gtid_seq_no= this->seq_no; thd->variables.gtid_seq_no= this->seq_no;
if (opt_gtid_strict_mode && opt_bin_log && opt_log_slave_updates)
{
/* Need to reset prior "ok" status to give an error. */
thd->clear_error();
thd->stmt_da->reset_diagnostics_area();
if (mysql_bin_log.check_strict_gtid_sequence(this->domain_id,
this->server_id, this->seq_no))
return 1;
}
if (flags2 & FL_STANDALONE) if (flags2 & FL_STANDALONE)
return 0; return 0;
......
...@@ -677,7 +677,7 @@ mysql_mutex_t ...@@ -677,7 +677,7 @@ mysql_mutex_t
mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats, mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats,
LOCK_global_table_stats, LOCK_global_index_stats; LOCK_global_table_stats, LOCK_global_index_stats;
mysql_mutex_t LOCK_gtid_counter, LOCK_rpl_gtid_state; mysql_mutex_t LOCK_rpl_gtid_state;
/** /**
The below lock protects access to two global server variables: The below lock protects access to two global server variables:
...@@ -776,7 +776,7 @@ PSI_mutex_key key_LOCK_stats, ...@@ -776,7 +776,7 @@ PSI_mutex_key key_LOCK_stats,
key_LOCK_global_index_stats, key_LOCK_global_index_stats,
key_LOCK_wakeup_ready; key_LOCK_wakeup_ready;
PSI_mutex_key key_LOCK_gtid_counter, key_LOCK_rpl_gtid_state; PSI_mutex_key key_LOCK_rpl_gtid_state;
PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered; PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered;
...@@ -821,7 +821,6 @@ static PSI_mutex_info all_server_mutexes[]= ...@@ -821,7 +821,6 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_global_table_stats, "LOCK_global_table_stats", PSI_FLAG_GLOBAL}, { &key_LOCK_global_table_stats, "LOCK_global_table_stats", PSI_FLAG_GLOBAL},
{ &key_LOCK_global_index_stats, "LOCK_global_index_stats", PSI_FLAG_GLOBAL}, { &key_LOCK_global_index_stats, "LOCK_global_index_stats", PSI_FLAG_GLOBAL},
{ &key_LOCK_wakeup_ready, "THD::LOCK_wakeup_ready", 0}, { &key_LOCK_wakeup_ready, "THD::LOCK_wakeup_ready", 0},
{ &key_LOCK_gtid_counter, "LOCK_gtid_counter", PSI_FLAG_GLOBAL},
{ &key_LOCK_rpl_gtid_state, "LOCK_rpl_gtid_state", PSI_FLAG_GLOBAL}, { &key_LOCK_rpl_gtid_state, "LOCK_rpl_gtid_state", PSI_FLAG_GLOBAL},
{ &key_LOCK_thd_data, "THD::LOCK_thd_data", 0}, { &key_LOCK_thd_data, "THD::LOCK_thd_data", 0},
{ &key_LOCK_user_conn, "LOCK_user_conn", PSI_FLAG_GLOBAL}, { &key_LOCK_user_conn, "LOCK_user_conn", PSI_FLAG_GLOBAL},
...@@ -1294,10 +1293,7 @@ struct st_VioSSLFd *ssl_acceptor_fd; ...@@ -1294,10 +1293,7 @@ struct st_VioSSLFd *ssl_acceptor_fd;
*/ */
uint connection_count= 0, extra_connection_count= 0; uint connection_count= 0, extra_connection_count= 0;
/** my_bool opt_gtid_strict_mode= FALSE;
Running counter for generating new GTIDs locally.
*/
uint64 global_gtid_counter= 0;
/* Function declarations */ /* Function declarations */
...@@ -1977,7 +1973,6 @@ static void clean_up_mutexes() ...@@ -1977,7 +1973,6 @@ static void clean_up_mutexes()
mysql_mutex_destroy(&LOCK_global_user_client_stats); mysql_mutex_destroy(&LOCK_global_user_client_stats);
mysql_mutex_destroy(&LOCK_global_table_stats); mysql_mutex_destroy(&LOCK_global_table_stats);
mysql_mutex_destroy(&LOCK_global_index_stats); mysql_mutex_destroy(&LOCK_global_index_stats);
mysql_mutex_destroy(&LOCK_gtid_counter);
mysql_mutex_destroy(&LOCK_rpl_gtid_state); mysql_mutex_destroy(&LOCK_rpl_gtid_state);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
mysql_mutex_destroy(&LOCK_des_key_file); mysql_mutex_destroy(&LOCK_des_key_file);
...@@ -4089,8 +4084,6 @@ static int init_thread_environment() ...@@ -4089,8 +4084,6 @@ static int init_thread_environment()
&LOCK_global_table_stats, MY_MUTEX_INIT_FAST); &LOCK_global_table_stats, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_global_index_stats, mysql_mutex_init(key_LOCK_global_index_stats,
&LOCK_global_index_stats, MY_MUTEX_INIT_FAST); &LOCK_global_index_stats, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_gtid_counter,
&LOCK_gtid_counter, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_rpl_gtid_state, mysql_mutex_init(key_LOCK_rpl_gtid_state,
&LOCK_rpl_gtid_state, MY_MUTEX_INIT_SLOW); &LOCK_rpl_gtid_state, MY_MUTEX_INIT_SLOW);
mysql_mutex_init(key_LOCK_prepare_ordered, &LOCK_prepare_ordered, mysql_mutex_init(key_LOCK_prepare_ordered, &LOCK_prepare_ordered,
......
...@@ -253,7 +253,7 @@ extern PSI_mutex_key key_LOCK_stats, ...@@ -253,7 +253,7 @@ extern PSI_mutex_key key_LOCK_stats,
key_LOCK_global_user_client_stats, key_LOCK_global_table_stats, key_LOCK_global_user_client_stats, key_LOCK_global_table_stats,
key_LOCK_global_index_stats, key_LOCK_wakeup_ready; key_LOCK_global_index_stats, key_LOCK_wakeup_ready;
extern PSI_mutex_key key_LOCK_gtid_counter, key_LOCK_rpl_gtid_state; extern PSI_mutex_key key_LOCK_rpl_gtid_state;
extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger,
key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave, key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave,
...@@ -345,7 +345,7 @@ extern mysql_mutex_t ...@@ -345,7 +345,7 @@ extern mysql_mutex_t
LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_slave_list, LOCK_active_mi, LOCK_manager,
LOCK_global_system_variables, LOCK_user_conn, LOCK_global_system_variables, LOCK_user_conn,
LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count; LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count;
extern mysql_mutex_t LOCK_gtid_counter, LOCK_rpl_gtid_state; extern mysql_mutex_t LOCK_rpl_gtid_state;
extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count; extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count;
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
extern mysql_mutex_t LOCK_des_key_file; extern mysql_mutex_t LOCK_des_key_file;
...@@ -541,6 +541,7 @@ extern handlerton *maria_hton; ...@@ -541,6 +541,7 @@ extern handlerton *maria_hton;
extern uint extra_connection_count; extern uint extra_connection_count;
extern uint64 global_gtid_counter; extern uint64 global_gtid_counter;
extern my_bool opt_gtid_strict_mode;
extern my_bool opt_userstat_running, debug_assert_if_crashed_table; extern my_bool opt_userstat_running, debug_assert_if_crashed_table;
extern uint mysqld_extra_port; extern uint mysqld_extra_port;
extern ulong opt_progress_report_time; extern ulong opt_progress_report_time;
......
...@@ -370,7 +370,10 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, ...@@ -370,7 +370,10 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
} }
table->file->ha_index_end(); table->file->ha_index_end();
mysql_bin_log.bump_seq_no_counter_if_needed(gtid->seq_no); if(!err && opt_bin_log &&
(err= mysql_bin_log.bump_seq_no_counter_if_needed(gtid->domain_id,
gtid->seq_no)))
my_error(ER_OUT_OF_RESOURCES, MYF(0));
end: end:
...@@ -719,7 +722,7 @@ rpl_binlog_state::load(struct rpl_gtid *list, uint32 count) ...@@ -719,7 +722,7 @@ rpl_binlog_state::load(struct rpl_gtid *list, uint32 count)
reset(); reset();
for (i= 0; i < count; ++i) for (i= 0; i < count; ++i)
{ {
if (update(&(list[i]))) if (update(&(list[i]), false))
return true; return true;
} }
return false; return false;
...@@ -741,48 +744,111 @@ rpl_binlog_state::~rpl_binlog_state() ...@@ -741,48 +744,111 @@ rpl_binlog_state::~rpl_binlog_state()
Returns 0 for ok, 1 for error. Returns 0 for ok, 1 for error.
*/ */
int int
rpl_binlog_state::update(const struct rpl_gtid *gtid) rpl_binlog_state::update(const struct rpl_gtid *gtid, bool strict)
{ {
rpl_gtid *lookup_gtid;
element *elem; element *elem;
elem= (element *)my_hash_search(&hash, (const uchar *)(&gtid->domain_id), 0); if ((elem= (element *)my_hash_search(&hash,
if (elem) (const uchar *)(&gtid->domain_id), 0)))
{ {
/* if (strict && elem->last_gtid && elem->last_gtid->seq_no >= gtid->seq_no)
By far the most common case is that successive events within same
replication domain have the same server id (it changes only when
switching to a new master). So save a hash lookup in this case.
*/
if (likely(elem->last_gtid->server_id == gtid->server_id))
{ {
elem->last_gtid->seq_no= gtid->seq_no; my_error(ER_GTID_STRICT_OUT_OF_ORDER, MYF(0), gtid->domain_id,
return 0; gtid->server_id, gtid->seq_no, elem->last_gtid->domain_id,
elem->last_gtid->server_id, elem->last_gtid->seq_no);
return 1;
} }
if (elem->seq_no_counter < gtid->seq_no)
elem->seq_no_counter= gtid->seq_no;
if (!elem->update_element(gtid))
return 0;
}
else if (!alloc_element(gtid))
return 0;
lookup_gtid= (rpl_gtid *) my_error(ER_OUT_OF_RESOURCES, MYF(0));
my_hash_search(&elem->hash, (const uchar *)&gtid->server_id, 0); return 1;
if (lookup_gtid) }
{
lookup_gtid->seq_no= gtid->seq_no;
elem->last_gtid= lookup_gtid; /*
Fill in a new GTID, allocating next sequence number, and update state
accordingly.
*/
int
rpl_binlog_state::update_with_next_gtid(uint32 domain_id, uint32 server_id,
rpl_gtid *gtid)
{
element *elem;
gtid->domain_id= domain_id;
gtid->server_id= server_id;
if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id), 0)))
{
gtid->seq_no= ++elem->seq_no_counter;
if (!elem->update_element(gtid))
return 0; return 0;
} }
else
{
gtid->seq_no= 1;
if (!alloc_element(gtid))
return 0;
}
/* Allocate a new GTID and insert it. */ my_error(ER_OUT_OF_RESOURCES, MYF(0));
lookup_gtid= (rpl_gtid *)my_malloc(sizeof(*lookup_gtid), MYF(MY_WME)); return 1;
if (!lookup_gtid) }
return 1;
memcpy(lookup_gtid, gtid, sizeof(*lookup_gtid));
if (my_hash_insert(&elem->hash, (const uchar *)lookup_gtid)) /* Helper functions for update. */
{ int
my_free(lookup_gtid); rpl_binlog_state::element::update_element(const rpl_gtid *gtid)
return 1; {
} rpl_gtid *lookup_gtid;
elem->last_gtid= lookup_gtid;
/*
By far the most common case is that successive events within same
replication domain have the same server id (it changes only when
switching to a new master). So save a hash lookup in this case.
*/
if (likely(last_gtid && last_gtid->server_id == gtid->server_id))
{
last_gtid->seq_no= gtid->seq_no;
return 0;
}
lookup_gtid= (rpl_gtid *)
my_hash_search(&hash, (const uchar *)&gtid->server_id, 0);
if (lookup_gtid)
{
lookup_gtid->seq_no= gtid->seq_no;
last_gtid= lookup_gtid;
return 0; return 0;
} }
/* Allocate a new GTID and insert it. */
lookup_gtid= (rpl_gtid *)my_malloc(sizeof(*lookup_gtid), MYF(MY_WME));
if (!lookup_gtid)
return 1;
memcpy(lookup_gtid, gtid, sizeof(*lookup_gtid));
if (my_hash_insert(&hash, (const uchar *)lookup_gtid))
{
my_free(lookup_gtid);
return 1;
}
last_gtid= lookup_gtid;
return 0;
}
int
rpl_binlog_state::alloc_element(const rpl_gtid *gtid)
{
element *elem;
rpl_gtid *lookup_gtid;
/* First time we see this domain_id; allocate a new element. */ /* First time we see this domain_id; allocate a new element. */
elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME)); elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME));
lookup_gtid= (rpl_gtid *)my_malloc(sizeof(*lookup_gtid), MYF(MY_WME)); lookup_gtid= (rpl_gtid *)my_malloc(sizeof(*lookup_gtid), MYF(MY_WME));
...@@ -793,6 +859,7 @@ rpl_binlog_state::update(const struct rpl_gtid *gtid) ...@@ -793,6 +859,7 @@ rpl_binlog_state::update(const struct rpl_gtid *gtid)
offsetof(rpl_gtid, server_id), sizeof(uint32), NULL, my_free, offsetof(rpl_gtid, server_id), sizeof(uint32), NULL, my_free,
HASH_UNIQUE); HASH_UNIQUE);
elem->last_gtid= lookup_gtid; elem->last_gtid= lookup_gtid;
elem->seq_no_counter= gtid->seq_no;
memcpy(lookup_gtid, gtid, sizeof(*lookup_gtid)); memcpy(lookup_gtid, gtid, sizeof(*lookup_gtid));
if (0 == my_hash_insert(&elem->hash, (const uchar *)lookup_gtid)) if (0 == my_hash_insert(&elem->hash, (const uchar *)lookup_gtid))
{ {
...@@ -812,23 +879,64 @@ rpl_binlog_state::update(const struct rpl_gtid *gtid) ...@@ -812,23 +879,64 @@ rpl_binlog_state::update(const struct rpl_gtid *gtid)
} }
uint64 /*
rpl_binlog_state::seq_no_from_state() Check that a new GTID can be logged without creating an out-of-order
sequence number with existing GTIDs.
*/
bool
rpl_binlog_state::check_strict_sequence(uint32 domain_id, uint32 server_id,
uint64 seq_no)
{ {
ulong i, j; element *elem;
uint64 seq_no= 0;
for (i= 0; i < hash.records; ++i) if ((elem= (element *)my_hash_search(&hash,
(const uchar *)(&domain_id), 0)) &&
elem->last_gtid && elem->last_gtid->seq_no >= seq_no)
{ {
element *e= (element *)my_hash_element(&hash, i); my_error(ER_GTID_STRICT_OUT_OF_ORDER, MYF(0), domain_id, server_id, seq_no,
for (j= 0; j < e->hash.records; ++j) elem->last_gtid->domain_id, elem->last_gtid->server_id,
{ elem->last_gtid->seq_no);
const rpl_gtid *gtid= (const rpl_gtid *)my_hash_element(&e->hash, j); return 1;
if (gtid->seq_no > seq_no)
seq_no= gtid->seq_no;
}
} }
return seq_no; return 0;
}
/*
When we see a new GTID that will not be binlogged (eg. slave thread
with --log-slave-updates=0), then we need to remember to allocate any
GTID seq_no of our own within that domain starting from there.
Returns 0 if ok, non-zero if out-of-memory.
*/
int
rpl_binlog_state::bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no)
{
element *elem;
if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id), 0)))
{
if (elem->seq_no_counter < seq_no)
elem->seq_no_counter= seq_no;
return 0;
}
/* We need to allocate a new, empty element to remember the next seq_no. */
if (!(elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME))))
return 1;
elem->domain_id= domain_id;
my_hash_init(&elem->hash, &my_charset_bin, 32,
offsetof(rpl_gtid, server_id), sizeof(uint32), NULL, my_free,
HASH_UNIQUE);
elem->last_gtid= NULL;
elem->seq_no_counter= seq_no;
if (0 == my_hash_insert(&hash, (const uchar *)elem))
return 0;
my_hash_free(&elem->hash);
my_free(elem);
return 1;
} }
...@@ -849,6 +957,11 @@ rpl_binlog_state::write_to_iocache(IO_CACHE *dest) ...@@ -849,6 +957,11 @@ rpl_binlog_state::write_to_iocache(IO_CACHE *dest)
{ {
size_t res; size_t res;
element *e= (element *)my_hash_element(&hash, i); element *e= (element *)my_hash_element(&hash, i);
if (!e->last_gtid)
{
DBUG_ASSERT(e->hash.records == 0);
continue;
}
for (j= 0; j <= e->hash.records; ++j) for (j= 0; j <= e->hash.records; ++j)
{ {
const rpl_gtid *gtid; const rpl_gtid *gtid;
...@@ -890,7 +1003,7 @@ rpl_binlog_state::read_from_iocache(IO_CACHE *src) ...@@ -890,7 +1003,7 @@ rpl_binlog_state::read_from_iocache(IO_CACHE *src)
end= buf + res; end= buf + res;
if (gtid_parser_helper(&p, end, &gtid)) if (gtid_parser_helper(&p, end, &gtid))
return 1; return 1;
if (update(&gtid)) if (update(&gtid, false))
return 1; return 1;
} }
return 0; return 0;
...@@ -906,6 +1019,17 @@ rpl_binlog_state::find(uint32 domain_id, uint32 server_id) ...@@ -906,6 +1019,17 @@ rpl_binlog_state::find(uint32 domain_id, uint32 server_id)
return (rpl_gtid *)my_hash_search(&elem->hash, (const uchar *)&server_id, 0); return (rpl_gtid *)my_hash_search(&elem->hash, (const uchar *)&server_id, 0);
} }
rpl_gtid *
rpl_binlog_state::find_most_recent(uint32 domain_id)
{
element *elem;
elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0);
if (elem && elem->last_gtid)
return elem->last_gtid;
return NULL;
}
uint32 uint32
rpl_binlog_state::count() rpl_binlog_state::count()
...@@ -929,6 +1053,11 @@ rpl_binlog_state::get_gtid_list(rpl_gtid *gtid_list, uint32 list_size) ...@@ -929,6 +1053,11 @@ rpl_binlog_state::get_gtid_list(rpl_gtid *gtid_list, uint32 list_size)
for (i= 0; i < hash.records; ++i) for (i= 0; i < hash.records; ++i)
{ {
element *e= (element *)my_hash_element(&hash, i); element *e= (element *)my_hash_element(&hash, i);
if (!e->last_gtid)
{
DBUG_ASSERT(e->hash.records==0);
continue;
}
for (j= 0; j <= e->hash.records; ++j) for (j= 0; j <= e->hash.records; ++j)
{ {
const rpl_gtid *gtid; const rpl_gtid *gtid;
...@@ -965,16 +1094,22 @@ int ...@@ -965,16 +1094,22 @@ int
rpl_binlog_state::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size) rpl_binlog_state::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size)
{ {
uint32 i; uint32 i;
uint32 alloc_size, out_size;
*size= hash.records; alloc_size= hash.records;
if (!(*list= (rpl_gtid *)my_malloc(*size * sizeof(rpl_gtid), MYF(MY_WME)))) if (!(*list= (rpl_gtid *)my_malloc(alloc_size * sizeof(rpl_gtid),
MYF(MY_WME))))
return 1; return 1;
for (i= 0; i < *size; ++i) out_size= 0;
for (i= 0; i < alloc_size; ++i)
{ {
element *e= (element *)my_hash_element(&hash, i); element *e= (element *)my_hash_element(&hash, i);
memcpy(&((*list)[i]), e->last_gtid, sizeof(rpl_gtid)); if (!e->last_gtid)
continue;
memcpy(&((*list)[out_size++]), e->last_gtid, sizeof(rpl_gtid));
} }
*size= out_size;
return 0; return 0;
} }
...@@ -988,7 +1123,8 @@ rpl_binlog_state::append_pos(String *str) ...@@ -988,7 +1123,8 @@ rpl_binlog_state::append_pos(String *str)
for (i= 0; i < hash.records; ++i) for (i= 0; i < hash.records; ++i)
{ {
element *e= (element *)my_hash_element(&hash, i); element *e= (element *)my_hash_element(&hash, i);
if (rpl_slave_state_tostring_helper(str, e->last_gtid, &first)) if (e->last_gtid &&
rpl_slave_state_tostring_helper(str, e->last_gtid, &first))
return true; return true;
} }
......
...@@ -131,6 +131,10 @@ struct rpl_binlog_state ...@@ -131,6 +131,10 @@ struct rpl_binlog_state
HASH hash; /* Containing all server_id for one domain_id */ HASH hash; /* Containing all server_id for one domain_id */
/* The most recent entry in the hash. */ /* The most recent entry in the hash. */
rpl_gtid *last_gtid; rpl_gtid *last_gtid;
/* Counter to allocate next seq_no for this domain. */
uint64 seq_no_counter;
int update_element(const rpl_gtid *gtid);
}; };
/* Mapping from domain_id to collection of elements. */ /* Mapping from domain_id to collection of elements. */
HASH hash; HASH hash;
...@@ -144,8 +148,12 @@ struct rpl_binlog_state ...@@ -144,8 +148,12 @@ struct rpl_binlog_state
void reset(); void reset();
void free(); void free();
bool load(struct rpl_gtid *list, uint32 count); bool load(struct rpl_gtid *list, uint32 count);
int update(const struct rpl_gtid *gtid); int update(const struct rpl_gtid *gtid, bool strict);
uint64 seq_no_from_state(); int update_with_next_gtid(uint32 domain_id, uint32 server_id,
rpl_gtid *gtid);
int alloc_element(const rpl_gtid *gtid);
bool check_strict_sequence(uint32 domain_id, uint32 server_id, uint64 seq_no);
int bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no);
int write_to_iocache(IO_CACHE *dest); int write_to_iocache(IO_CACHE *dest);
int read_from_iocache(IO_CACHE *src); int read_from_iocache(IO_CACHE *src);
uint32 count(); uint32 count();
...@@ -153,6 +161,7 @@ struct rpl_binlog_state ...@@ -153,6 +161,7 @@ struct rpl_binlog_state
int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size); int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size);
bool append_pos(String *str); bool append_pos(String *str);
rpl_gtid *find(uint32 domain_id, uint32 server_id); rpl_gtid *find(uint32 domain_id, uint32 server_id);
rpl_gtid *find_most_recent(uint32 domain_id);
}; };
......
...@@ -1397,7 +1397,6 @@ rpl_load_gtid_slave_state(THD *thd) ...@@ -1397,7 +1397,6 @@ rpl_load_gtid_slave_state(THD *thd)
HASH hash; HASH hash;
int err= 0; int err= 0;
uint32 i; uint32 i;
uint64 highest_seq_no= 0;
DBUG_ENTER("rpl_load_gtid_slave_state"); DBUG_ENTER("rpl_load_gtid_slave_state");
rpl_global_gtid_slave_state.lock(); rpl_global_gtid_slave_state.lock();
...@@ -1450,8 +1449,6 @@ rpl_load_gtid_slave_state(THD *thd) ...@@ -1450,8 +1449,6 @@ rpl_load_gtid_slave_state(THD *thd)
DBUG_PRINT("info", ("Read slave state row: %u-%u-%lu sub_id=%lu\n", DBUG_PRINT("info", ("Read slave state row: %u-%u-%lu sub_id=%lu\n",
(unsigned)domain_id, (unsigned)server_id, (unsigned)domain_id, (unsigned)server_id,
(ulong)seq_no, (ulong)sub_id)); (ulong)seq_no, (ulong)sub_id));
if (seq_no > highest_seq_no)
highest_seq_no= seq_no;
if ((rec= my_hash_search(&hash, (const uchar *)&domain_id, 0))) if ((rec= my_hash_search(&hash, (const uchar *)&domain_id, 0)))
{ {
...@@ -1495,6 +1492,14 @@ rpl_load_gtid_slave_state(THD *thd) ...@@ -1495,6 +1492,14 @@ rpl_load_gtid_slave_state(THD *thd)
rpl_global_gtid_slave_state.unlock(); rpl_global_gtid_slave_state.unlock();
goto end; goto end;
} }
if (opt_bin_log &&
mysql_bin_log.bump_seq_no_counter_if_needed(entry->gtid.domain_id,
entry->gtid.seq_no))
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
rpl_global_gtid_slave_state.unlock();
goto end;
}
} }
rpl_global_gtid_slave_state.loaded= true; rpl_global_gtid_slave_state.loaded= true;
rpl_global_gtid_slave_state.unlock(); rpl_global_gtid_slave_state.unlock();
...@@ -1514,7 +1519,6 @@ rpl_load_gtid_slave_state(THD *thd) ...@@ -1514,7 +1519,6 @@ rpl_load_gtid_slave_state(THD *thd)
thd->mdl_context.release_transactional_locks(); thd->mdl_context.release_transactional_locks();
} }
my_hash_free(&hash); my_hash_free(&hash);
mysql_bin_log.bump_seq_no_counter_if_needed(highest_seq_no);
DBUG_RETURN(err); DBUG_RETURN(err);
} }
......
...@@ -6545,3 +6545,7 @@ ER_MASTER_GTID_POS_MISSING_DOMAIN ...@@ -6545,3 +6545,7 @@ ER_MASTER_GTID_POS_MISSING_DOMAIN
eng "Specified value for @@gtid_slave_pos contains no value for replication domain %u. This conflicts with the binary log which contains GTID %u-%u-%llu. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos." eng "Specified value for @@gtid_slave_pos contains no value for replication domain %u. This conflicts with the binary log which contains GTID %u-%u-%llu. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos."
ER_UNTIL_REQUIRES_USING_GTID ER_UNTIL_REQUIRES_USING_GTID
eng "START SLAVE UNTIL master_gtid_pos requires that slave is using GTID" eng "START SLAVE UNTIL master_gtid_pos requires that slave is using GTID"
ER_GTID_STRICT_OUT_OF_ORDER
eng "An attempt was made to binlog GTID %u-%u-%llu which would create an out-of-order sequence number with existing GTID %u-%u-%llu, and gtid strict mode is enabled."
ER_GTID_START_FROM_BINLOG_HOLE
eng "The binlog on the master is missing the GTID %u-%u-%llu requested by the slave (even though both a prior and a subsequent sequence number does exist), and GTID strict mode is enabled"
...@@ -1824,8 +1824,8 @@ when it try to get the value of TIME_ZONE global variable from master."; ...@@ -1824,8 +1824,8 @@ when it try to get the value of TIME_ZONE global variable from master.";
{ {
int rc; int rc;
char str_buf[256]; char str_buf[256];
String connect_state(str_buf, sizeof(str_buf), system_charset_info); String query_str(str_buf, sizeof(str_buf), system_charset_info);
connect_state.length(0); query_str.length(0);
/* /*
Read the master @@GLOBAL.gtid_domain_id variable. Read the master @@GLOBAL.gtid_domain_id variable.
...@@ -1848,9 +1848,9 @@ when it try to get the value of TIME_ZONE global variable from master."; ...@@ -1848,9 +1848,9 @@ when it try to get the value of TIME_ZONE global variable from master.";
mysql_free_result(master_res); mysql_free_result(master_res);
master_res= NULL; master_res= NULL;
connect_state.append(STRING_WITH_LEN("SET @slave_connect_state='"), query_str.append(STRING_WITH_LEN("SET @slave_connect_state='"),
system_charset_info); system_charset_info);
if (rpl_append_gtid_state(&connect_state, if (rpl_append_gtid_state(&query_str,
mi->using_gtid == mi->using_gtid ==
Master_info::USE_GTID_CURRENT_POS)) Master_info::USE_GTID_CURRENT_POS))
{ {
...@@ -1860,9 +1860,9 @@ when it try to get the value of TIME_ZONE global variable from master."; ...@@ -1860,9 +1860,9 @@ when it try to get the value of TIME_ZONE global variable from master.";
sprintf(err_buff, "%s Error: Out of memory", errmsg); sprintf(err_buff, "%s Error: Out of memory", errmsg);
goto err; goto err;
} }
connect_state.append(STRING_WITH_LEN("'"), system_charset_info); query_str.append(STRING_WITH_LEN("'"), system_charset_info);
rc= mysql_real_query(mysql, connect_state.ptr(), connect_state.length()); rc= mysql_real_query(mysql, query_str.ptr(), query_str.length());
if (rc) if (rc)
{ {
err_code= mysql_errno(mysql); err_code= mysql_errno(mysql);
...@@ -1883,12 +1883,45 @@ when it try to get the value of TIME_ZONE global variable from master."; ...@@ -1883,12 +1883,45 @@ when it try to get the value of TIME_ZONE global variable from master.";
} }
} }
query_str.length(0);
if (query_str.append(STRING_WITH_LEN("SET @slave_gtid_strict_mode="),
system_charset_info) ||
query_str.append_ulonglong(opt_gtid_strict_mode != false))
{
err_code= ER_OUTOFMEMORY;
errmsg= "The slave I/O thread stops because a fatal out-of-memory "
"error is encountered when it tries to set @slave_gtid_strict_mode.";
sprintf(err_buff, "%s Error: Out of memory", errmsg);
goto err;
}
rc= mysql_real_query(mysql, query_str.ptr(), query_str.length());
if (rc)
{
err_code= mysql_errno(mysql);
if (is_network_error(err_code))
{
mi->report(ERROR_LEVEL, err_code,
"Setting @slave_gtid_strict_mode failed with error: %s",
mysql_error(mysql));
goto network_err;
}
else
{
/* Fatal error */
errmsg= "The slave I/O thread stops because a fatal error is "
"encountered when it tries to set @slave_gtid_strict_mode.";
sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql));
goto err;
}
}
if (mi->rli.until_condition == Relay_log_info::UNTIL_GTID) if (mi->rli.until_condition == Relay_log_info::UNTIL_GTID)
{ {
connect_state.length(0); query_str.length(0);
connect_state.append(STRING_WITH_LEN("SET @slave_until_gtid='"), query_str.append(STRING_WITH_LEN("SET @slave_until_gtid='"),
system_charset_info); system_charset_info);
if (mi->rli.until_gtid_pos.append_to_string(&connect_state)) if (mi->rli.until_gtid_pos.append_to_string(&query_str))
{ {
err_code= ER_OUTOFMEMORY; err_code= ER_OUTOFMEMORY;
errmsg= "The slave I/O thread stops because a fatal out-of-memory " errmsg= "The slave I/O thread stops because a fatal out-of-memory "
...@@ -1896,9 +1929,9 @@ when it try to get the value of TIME_ZONE global variable from master."; ...@@ -1896,9 +1929,9 @@ when it try to get the value of TIME_ZONE global variable from master.";
sprintf(err_buff, "%s Error: Out of memory", errmsg); sprintf(err_buff, "%s Error: Out of memory", errmsg);
goto err; goto err;
} }
connect_state.append(STRING_WITH_LEN("'"), system_charset_info); query_str.append(STRING_WITH_LEN("'"), system_charset_info);
rc= mysql_real_query(mysql, connect_state.ptr(), connect_state.length()); rc= mysql_real_query(mysql, query_str.ptr(), query_str.length());
if (rc) if (rc)
{ {
err_code= mysql_errno(mysql); err_code= mysql_errno(mysql);
......
This diff is collapsed.
...@@ -1215,6 +1215,26 @@ static Sys_var_uint Sys_gtid_domain_id( ...@@ -1215,6 +1215,26 @@ static Sys_var_uint Sys_gtid_domain_id(
BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(check_has_super)); ON_CHECK(check_has_super));
static bool check_gtid_seq_no(sys_var *self, THD *thd, set_var *var)
{
uint32 domain_id, server_id;
uint64_t seq_no;
if (check_has_super(self, thd, var))
return true;
domain_id= thd->variables.gtid_domain_id;
server_id= thd->variables.server_id;
seq_no= (uint64)var->value->val_uint();
DBUG_EXECUTE_IF("ignore_set_gtid_seq_no_check", return 0;);
if (opt_gtid_strict_mode && opt_bin_log &&
mysql_bin_log.check_strict_gtid_sequence(domain_id, server_id, seq_no))
return true;
return false;
}
static Sys_var_ulonglong Sys_gtid_seq_no( static Sys_var_ulonglong Sys_gtid_seq_no(
"gtid_seq_no", "gtid_seq_no",
"Internal server usage, for replication with global transaction id. " "Internal server usage, for replication with global transaction id. "
...@@ -1224,7 +1244,7 @@ static Sys_var_ulonglong Sys_gtid_seq_no( ...@@ -1224,7 +1244,7 @@ static Sys_var_ulonglong Sys_gtid_seq_no(
SESSION_ONLY(gtid_seq_no), SESSION_ONLY(gtid_seq_no),
NO_CMD_LINE, VALID_RANGE(0, ULONGLONG_MAX), DEFAULT(0), NO_CMD_LINE, VALID_RANGE(0, ULONGLONG_MAX), DEFAULT(0),
BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(check_has_super)); ON_CHECK(check_gtid_seq_no));
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
...@@ -1364,6 +1384,15 @@ static Sys_var_gtid_slave_pos Sys_gtid_slave_pos( ...@@ -1364,6 +1384,15 @@ static Sys_var_gtid_slave_pos Sys_gtid_slave_pos(
"The list of global transaction IDs that were last replicated on the " "The list of global transaction IDs that were last replicated on the "
"server, one for each replication domain.", "server, one for each replication domain.",
GLOBAL_VAR(opt_gtid_slave_pos_dummy), NO_CMD_LINE); GLOBAL_VAR(opt_gtid_slave_pos_dummy), NO_CMD_LINE);
static Sys_var_mybool Sys_gtid_strict_mode(
"gtid_strict_mode",
"Enforce strict seq_no ordering of events in the binary log. Slave "
"stops with an error if it encounters an event that would cause it to "
"generate an out-of-order binlog if executed.",
GLOBAL_VAR(opt_gtid_strict_mode),
CMD_LINE(OPT_ARG), DEFAULT(FALSE));
#endif #endif
......
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