Merge of MDEV-4984, MDEV-4726, and MDEV-5636 into 10.0-base.
MDEV-4984: Implement MASTER_GTID_WAIT() and @@LAST_GTID. MDEV-4726: Race in mysql-test/suite/rpl/t/rpl_gtid_stop_start.test MDEV-5636: Deadlock in RESET MASTER
This commit is contained in:
commit
fefdb576bb
@ -915,6 +915,7 @@ static COMMANDS commands[] = {
|
||||
{ "MAKE_SET", 0, 0, 0, ""},
|
||||
{ "MAKEDATE", 0, 0, 0, ""},
|
||||
{ "MAKETIME", 0, 0, 0, ""},
|
||||
{ "MASTER_GTID_WAIT", 0, 0, 0, ""},
|
||||
{ "MASTER_POS_WAIT", 0, 0, 0, ""},
|
||||
{ "MAX", 0, 0, 0, ""},
|
||||
{ "MBRCONTAINS", 0, 0, 0, ""},
|
||||
|
@ -51,6 +51,7 @@ typedef struct st_queue {
|
||||
|
||||
#define queue_first_element(queue) 1
|
||||
#define queue_last_element(queue) (queue)->elements
|
||||
#define queue_empty(queue) ((queue)->elements == 0)
|
||||
#define queue_top(queue) ((queue)->root[1])
|
||||
#define queue_element(queue,index) ((queue)->root[index])
|
||||
#define queue_end(queue) ((queue)->root[(queue)->elements])
|
||||
|
28
mysql-test/include/save_master_gtid.inc
Normal file
28
mysql-test/include/save_master_gtid.inc
Normal file
@ -0,0 +1,28 @@
|
||||
# ==== Purpose ====
|
||||
#
|
||||
# Save the current binlog GTID position on the master, to be used
|
||||
# with include/sync_with_master_gtid.inc.
|
||||
#
|
||||
#
|
||||
# ==== Usage ====
|
||||
#
|
||||
# [--let $rpl_debug= 1]
|
||||
# --source include/save_master_gtid.inc
|
||||
#
|
||||
# Parameters:
|
||||
# $rpl_debug
|
||||
# See include/rpl_init.inc
|
||||
|
||||
|
||||
--let $include_filename= save_master_gtid.inc
|
||||
--source include/begin_include_file.inc
|
||||
|
||||
--let $master_pos= `SELECT @@gtid_binlog_pos`
|
||||
|
||||
if ($rpl_debug)
|
||||
{
|
||||
--echo save_master_gtid saved master_pos='$master_pos'
|
||||
}
|
||||
|
||||
--let $include_filename= save_master_gtid.inc
|
||||
--source include/end_include_file.inc
|
48
mysql-test/include/sync_with_master_gtid.inc
Normal file
48
mysql-test/include/sync_with_master_gtid.inc
Normal file
@ -0,0 +1,48 @@
|
||||
# ==== Purpose ====
|
||||
#
|
||||
# Wait until the slave has reached a certain GTID position.
|
||||
# Similar to --sync_with_master, but using GTID instead of old-style
|
||||
# binlog file/offset coordinates.
|
||||
#
|
||||
#
|
||||
# ==== Usage ====
|
||||
#
|
||||
# --let $master_pos= `SELECT @@GLOBAL.gtid_binlog_pos`
|
||||
# [--let $slave_timeout= NUMBER]
|
||||
# [--let $rpl_debug= 1]
|
||||
# --source include/sync_with_master_gtid.inc
|
||||
#
|
||||
# Syncs slave to the specified GTID position.
|
||||
#
|
||||
# Must be called on the slave.
|
||||
#
|
||||
# Parameters:
|
||||
# $master_pos
|
||||
# The GTID position to sync to. Typically obtained from
|
||||
# @@GLOBAL.gtid_binlog_pos on the master.
|
||||
#
|
||||
# $slave_timeout
|
||||
# Timeout in seconds. The default is 2 minutes.
|
||||
#
|
||||
# $rpl_debug
|
||||
# See include/rpl_init.inc
|
||||
|
||||
--let $include_filename= sync_with_master_gtid.inc
|
||||
--source include/begin_include_file.inc
|
||||
|
||||
let $_slave_timeout= $slave_timeout;
|
||||
if (!$_slave_timeout)
|
||||
{
|
||||
let $_slave_timeout= 120;
|
||||
}
|
||||
|
||||
--let $_result= `SELECT master_gtid_wait('$master_pos', $_slave_timeout)`
|
||||
if ($_result == -1)
|
||||
{
|
||||
--let $_current_gtid_pos= `SELECT @@GLOBAL.gtid_slave_pos`
|
||||
--echo Timeout in master_gtid_wait('$master_pos', $_slave_timeout), current slave GTID position is: $_current_gtid_pos.
|
||||
--die Failed to sync with master
|
||||
}
|
||||
|
||||
--let $include_filename= sync_with_master_gtid.inc
|
||||
--source include/end_include_file.inc
|
@ -37,6 +37,7 @@ wait/synch/mutex/mysys/THR_LOCK_threads
|
||||
wait/synch/mutex/mysys/TMPDIR_mutex
|
||||
wait/synch/mutex/sql/Cversion_lock
|
||||
wait/synch/mutex/sql/Event_scheduler::LOCK_scheduler_state
|
||||
wait/synch/mutex/sql/gtid_waiting::LOCK_gtid_waiting
|
||||
wait/synch/mutex/sql/hash_filo::lock
|
||||
wait/synch/mutex/sql/LOCK_active_mi
|
||||
wait/synch/mutex/sql/LOCK_audit_mask
|
||||
|
@ -7,13 +7,13 @@ NAME ENABLED TIMED
|
||||
wait/synch/mutex/sql/Cversion_lock YES YES
|
||||
wait/synch/mutex/sql/Delayed_insert::mutex YES YES
|
||||
wait/synch/mutex/sql/Event_scheduler::LOCK_scheduler_state YES YES
|
||||
wait/synch/mutex/sql/gtid_waiting::LOCK_gtid_waiting YES YES
|
||||
wait/synch/mutex/sql/hash_filo::lock YES YES
|
||||
wait/synch/mutex/sql/HA_DATA_PARTITION::LOCK_auto_inc YES YES
|
||||
wait/synch/mutex/sql/LOCK_active_mi YES YES
|
||||
wait/synch/mutex/sql/LOCK_audit_mask YES YES
|
||||
wait/synch/mutex/sql/LOCK_binlog_state YES YES
|
||||
wait/synch/mutex/sql/LOCK_commit_ordered YES YES
|
||||
wait/synch/mutex/sql/LOCK_connection_count YES YES
|
||||
select * from performance_schema.setup_instruments
|
||||
where name like 'Wait/Synch/Rwlock/sql/%'
|
||||
and name not in ('wait/synch/rwlock/sql/CRYPTO_dynlock_value::lock')
|
||||
|
@ -99,13 +99,13 @@ a b
|
||||
5 j1a
|
||||
*** Now move C to D, after letting it fall a little behind ***
|
||||
include/stop_slave.inc
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES (6, "i6b");
|
||||
INSERT INTO t2 VALUES (7, "i7b");
|
||||
COMMIT;
|
||||
include/save_master_gtid.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_4,
|
||||
MASTER_USE_GTID=CURRENT_POS;
|
||||
include/start_slave.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
a b
|
||||
1 i1
|
||||
@ -116,6 +116,7 @@ a b
|
||||
6 i6b
|
||||
7 i7b
|
||||
*** Now change everything back to what it was, to make rpl_end.inc happy
|
||||
include/sync_with_master_gtid.inc
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_MYPORT;
|
||||
include/start_slave.inc
|
||||
@ -123,10 +124,12 @@ include/wait_for_slave_to_start.inc
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SLAVE_MYPORT;
|
||||
include/start_slave.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_3;
|
||||
include/start_slave.inc
|
||||
DROP TABLE t1,t2;
|
||||
include/save_master_gtid.inc
|
||||
*** A few more checks for BINLOG_GTID_POS function ***
|
||||
SELECT BINLOG_GTID_POS();
|
||||
ERROR 42000: Incorrect parameter count in the call to native function 'BINLOG_GTID_POS'
|
||||
@ -163,6 +166,7 @@ NULL
|
||||
Warnings:
|
||||
Warning 1916 Got overflow when converting '18446744073709551616' to INT. Value truncated.
|
||||
*** Some tests of @@GLOBAL.gtid_binlog_state ***
|
||||
include/sync_with_master_gtid.inc
|
||||
include/stop_slave.inc
|
||||
SET @old_state= @@GLOBAL.gtid_binlog_state;
|
||||
SET GLOBAL gtid_binlog_state = '';
|
||||
@ -196,10 +200,121 @@ SET GLOBAL gtid_binlog_state = @old_state;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||
SET gtid_seq_no=100;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
include/save_master_gtid.inc
|
||||
include/start_slave.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
1
|
||||
Gtid_IO_Pos = '0-1-100'
|
||||
*** Test @@LAST_GTID and MASTER_GTID_WAIT() ***
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
include/stop_slave.inc
|
||||
SELECT @@last_gtid;
|
||||
@@last_gtid
|
||||
|
||||
SET gtid_seq_no=110;
|
||||
SELECT @@last_gtid;
|
||||
@@last_gtid
|
||||
|
||||
BEGIN;
|
||||
SELECT @@last_gtid;
|
||||
@@last_gtid
|
||||
|
||||
INSERT INTO t1 VALUES (2);
|
||||
SELECT @@last_gtid;
|
||||
@@last_gtid
|
||||
|
||||
COMMIT;
|
||||
SELECT @@last_gtid;
|
||||
@@last_gtid
|
||||
0-1-110
|
||||
SET @pos= '0-1-110';
|
||||
SELECT master_gtid_wait(NULL);
|
||||
master_gtid_wait(NULL)
|
||||
NULL
|
||||
SELECT master_gtid_wait('', NULL);
|
||||
master_gtid_wait('', NULL)
|
||||
0
|
||||
SELECT master_gtid_wait(@pos, 0.5);
|
||||
master_gtid_wait(@pos, 0.5)
|
||||
-1
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
SELECT master_gtid_wait(@pos);
|
||||
include/start_slave.inc
|
||||
master_gtid_wait(@pos)
|
||||
0
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
2
|
||||
include/stop_slave.inc
|
||||
SET gtid_domain_id= 1;
|
||||
INSERT INTO t1 VALUES (3);
|
||||
SET @pos= '1-1-1,0-1-110';
|
||||
SELECT master_gtid_wait(@pos, 0);
|
||||
master_gtid_wait(@pos, 0)
|
||||
-1
|
||||
SELECT * FROM t1 WHERE a >= 3;
|
||||
a
|
||||
SELECT master_gtid_wait(@pos, -1);
|
||||
include/start_slave.inc
|
||||
master_gtid_wait(@pos, -1)
|
||||
0
|
||||
SELECT * FROM t1 WHERE a >= 3;
|
||||
a
|
||||
3
|
||||
SELECT master_gtid_wait('1-1-1', 0);
|
||||
master_gtid_wait('1-1-1', 0)
|
||||
0
|
||||
SELECT master_gtid_wait('2-1-1,1-1-4,0-1-110');
|
||||
SELECT master_gtid_wait('0-1-1000', 0.5);
|
||||
SELECT master_gtid_wait('0-1-2000');
|
||||
SELECT master_gtid_wait('2-1-10');
|
||||
SELECT master_gtid_wait('2-1-6', 1);
|
||||
SELECT master_gtid_wait('2-1-5');
|
||||
SELECT master_gtid_wait('2-1-10');
|
||||
SELECT master_gtid_wait('2-1-5,1-1-4,0-1-110');
|
||||
SELECT master_gtid_wait('2-1-2');
|
||||
SELECT master_gtid_wait('1-1-1');
|
||||
master_gtid_wait('1-1-1')
|
||||
0
|
||||
SELECT master_gtid_wait('0-1-109');
|
||||
SELECT master_gtid_wait('2-1-2', 0.5);
|
||||
master_gtid_wait('2-1-2', 0.5)
|
||||
-1
|
||||
KILL QUERY KILL_ID;
|
||||
ERROR 70100: Query execution was interrupted
|
||||
SET gtid_domain_id=2;
|
||||
SET gtid_seq_no=2;
|
||||
INSERT INTO t1 VALUES (4);
|
||||
master_gtid_wait('2-1-2')
|
||||
0
|
||||
KILL CONNECTION KILL_ID;
|
||||
ERROR HY000: Lost connection to MySQL server during query
|
||||
SET gtid_domain_id=1;
|
||||
SET gtid_seq_no=4;
|
||||
INSERT INTO t1 VALUES (5);
|
||||
SET gtid_domain_id=2;
|
||||
SET gtid_seq_no=5;
|
||||
INSERT INTO t1 VALUES (6);
|
||||
master_gtid_wait('2-1-5,1-1-4,0-1-110')
|
||||
0
|
||||
master_gtid_wait('2-1-1,1-1-4,0-1-110')
|
||||
0
|
||||
master_gtid_wait('0-1-1000', 0.5)
|
||||
-1
|
||||
master_gtid_wait('2-1-6', 1)
|
||||
-1
|
||||
master_gtid_wait('0-1-109')
|
||||
0
|
||||
SET gtid_domain_id=2;
|
||||
SET gtid_seq_no=10;
|
||||
INSERT INTO t1 VALUES (7);
|
||||
master_gtid_wait('2-1-10')
|
||||
0
|
||||
master_gtid_wait('2-1-10')
|
||||
0
|
||||
DROP TABLE t1;
|
||||
include/rpl_end.inc
|
||||
|
@ -12,10 +12,14 @@ MASTER_USE_GTID=CURRENT_POS;
|
||||
INSERT INTO t1 VALUES (2,1);
|
||||
INSERT INTO t1 VALUES (3,1);
|
||||
include/start_slave.inc
|
||||
include/save_master_gtid.inc
|
||||
SET SESSION debug_dbug="+d,crash_dispatch_command_before";
|
||||
SELECT 1;
|
||||
Got one of the listed errors
|
||||
include/sync_with_master_gtid.inc
|
||||
INSERT INTO t1 VALUES (1000, 3);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
DROP TABLE t1;
|
||||
*** Test crashing the master mysqld and check that binlog state is recovered. ***
|
||||
include/stop_slave.inc
|
||||
@ -64,22 +68,32 @@ include/stop_slave.inc
|
||||
SET GLOBAL debug_dbug="+d,inject_crash_before_write_rpl_slave_state";
|
||||
START SLAVE;
|
||||
INSERT INTO t1 VALUES (4);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
include/stop_slave.inc
|
||||
SET GLOBAL debug_dbug="+d,crash_commit_before";
|
||||
START SLAVE;
|
||||
INSERT INTO t1 VALUES (5);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
include/stop_slave.inc
|
||||
SET GLOBAL debug_dbug="+d,crash_commit_after";
|
||||
START SLAVE;
|
||||
INSERT INTO t1 VALUES (6);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
include/stop_slave.inc
|
||||
SET GLOBAL debug_dbug="+d,inject_crash_before_flush_rli";
|
||||
START SLAVE;
|
||||
INSERT INTO t1 VALUES (7);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
include/stop_slave.inc
|
||||
SET GLOBAL debug_dbug="+d,inject_crash_after_flush_rli";
|
||||
START SLAVE;
|
||||
INSERT INTO t1 VALUES (8);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
|
@ -57,6 +57,7 @@ include/stop_slave.inc
|
||||
RESET MASTER;
|
||||
INSERT INTO t1 VALUES (2);
|
||||
INSERT INTO t1 VALUES (4);
|
||||
include/save_master_gtid.inc
|
||||
SET sql_log_bin = 0;
|
||||
INSERT INTO t1 VALUES (2);
|
||||
SET sql_log_bin = 1;
|
||||
@ -84,6 +85,7 @@ Warning 1948 Specified value for @@gtid_slave_pos contains no value for replicat
|
||||
RESET MASTER;
|
||||
SET GLOBAL gtid_slave_pos = "0-1-1";
|
||||
START SLAVE;
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
@ -93,6 +95,7 @@ a
|
||||
*** MDEV-4688: Empty value of @@GLOBAL.gtid_slave_pos ***
|
||||
include/stop_slave.inc
|
||||
INSERT INTO t1 VALUES (5);
|
||||
include/save_master_gtid.inc
|
||||
SET @old_dbug= @@GLOBAL.debug_dbug;
|
||||
SET GLOBAL debug_dbug="+d,dummy_disable_default_dbug_output";
|
||||
SET GLOBAL debug_dbug="+d,gtid_fail_after_record_gtid";
|
||||
@ -112,6 +115,7 @@ a
|
||||
4
|
||||
SET GLOBAL debug_dbug= @old_dbug;
|
||||
START SLAVE SQL_THREAD;
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
@ -136,6 +140,8 @@ SET GLOBAL gtid_slave_pos = "0-1-3";
|
||||
START SLAVE;
|
||||
include/wait_for_slave_to_start.inc
|
||||
INSERT INTO t1 VALUES (6);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
|
@ -23,6 +23,7 @@ START SLAVE;
|
||||
include/wait_for_slave_to_start.inc
|
||||
INSERT INTO t1 VALUES (3, 2);
|
||||
INSERT INTO t1 VALUES (4, 2);
|
||||
include/save_master_gtid.inc
|
||||
show binlog events from <binlog_start>;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
slave-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
@ -31,6 +32,7 @@ slave-bin.000001 # Query # # COMMIT
|
||||
slave-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4, 2)
|
||||
slave-bin.000001 # Query # # COMMIT
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a b
|
||||
1 1
|
||||
@ -41,9 +43,11 @@ include/stop_slave.inc
|
||||
RESET SLAVE;
|
||||
INSERT INTO t1 VALUES (5, 1);
|
||||
INSERT INTO t1 VALUES (6, 1);
|
||||
include/save_master_gtid.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_PORT,
|
||||
master_use_gtid = current_pos;
|
||||
START SLAVE;
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a b
|
||||
1 1
|
||||
|
@ -43,10 +43,12 @@ SET sql_log_bin=1;
|
||||
*** Test that we give warning when explict @@gtid_slave_pos=xxx that conflicts with what is in our binary log ***
|
||||
include/stop_slave.inc
|
||||
INSERT INTO t1 VALUES(3);
|
||||
include/save_master_gtid.inc
|
||||
SET GLOBAL gtid_slave_pos='0-1-3';
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_PORT,
|
||||
MASTER_USE_GTID=CURRENT_POS;
|
||||
include/start_slave.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER by a;
|
||||
a
|
||||
1
|
||||
@ -54,6 +56,7 @@ a
|
||||
3
|
||||
include/stop_slave.inc
|
||||
INSERT INTO t1 VALUES (4);
|
||||
include/save_master_gtid.inc
|
||||
INSERT INTO t1 VALUES (10);
|
||||
DELETE FROM t1 WHERE a=10;
|
||||
SET GLOBAL gtid_slave_pos='0-1-4';
|
||||
@ -62,6 +65,7 @@ Warning 1947 Specified GTID 0-1-4 conflicts with the binary log which contains a
|
||||
RESET MASTER;
|
||||
SET GLOBAL gtid_slave_pos='0-1-4';
|
||||
START SLAVE;
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER by a;
|
||||
a
|
||||
1
|
||||
@ -125,6 +129,8 @@ STOP SLAVE IO_THREAD;
|
||||
CHANGE MASTER TO MASTER_USE_GTID=CURRENT_POS;
|
||||
include/start_slave.inc
|
||||
INSERT INTO t1 VALUES(3);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
@ -136,6 +142,8 @@ SET SQL_LOG_BIN=1;
|
||||
*** Test reconnecting slave with GTID after purge logs on master. ***
|
||||
FLUSH LOGS;
|
||||
INSERT INTO t1 VALUES (4);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
include/stop_slave.inc
|
||||
FLUSH LOGS;
|
||||
FLUSH LOGS;
|
||||
@ -144,8 +152,10 @@ show binary logs;
|
||||
Log_name File_size
|
||||
master-bin.000004 #
|
||||
INSERT INTO t1 VALUES (5);
|
||||
include/save_master_gtid.inc
|
||||
CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_PORT;
|
||||
include/start_slave.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
@ -160,7 +170,9 @@ SET GLOBAL gtid_slave_pos="";
|
||||
RESET MASTER;
|
||||
TRUNCATE TABLE t1;
|
||||
INSERT INTO t1 VALUES (10);
|
||||
include/save_master_gtid.inc
|
||||
include/start_slave.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
10
|
||||
|
@ -14,10 +14,12 @@ master-bin.000002 #
|
||||
INSERT INTO t1 VALUES (2);
|
||||
FLUSH LOGS;
|
||||
INSERT INTO t1 VALUES (3);
|
||||
include/save_master_gtid.inc
|
||||
show binary logs;
|
||||
Log_name File_size
|
||||
master-bin.000002 #
|
||||
master-bin.000003 #
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
@ -43,6 +45,8 @@ master-bin.000003 #
|
||||
master-bin.000004 #
|
||||
master-bin.000005 #
|
||||
INSERT INTO t1 VALUES(5);
|
||||
include/save_master_gtid.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
|
@ -97,19 +97,16 @@ connection server_3;
|
||||
--source include/stop_slave.inc
|
||||
|
||||
connection server_1;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES (6, "i6b");
|
||||
INSERT INTO t2 VALUES (7, "i7b");
|
||||
COMMIT;
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
connection server_3;
|
||||
--replace_result $SERVER_MYPORT_4 SERVER_MYPORT_4
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_4,
|
||||
MASTER_USE_GTID=CURRENT_POS;
|
||||
--source include/start_slave.inc
|
||||
# This time, let's sync up without reference to binlog on D.
|
||||
--let $wait_condition= SELECT COUNT(*) = 7 FROM t2
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
|
||||
--echo *** Now change everything back to what it was, to make rpl_end.inc happy
|
||||
@ -118,8 +115,7 @@ connection server_2;
|
||||
# We need to sync up server_2 before switching. If it happened to have reached
|
||||
# the point 'UPDATE t2 SET b="j1a" WHERE a=5' it will fail to connect to
|
||||
# server_1, which is (deliberately) missing that transaction.
|
||||
--let $wait_condition= SELECT COUNT(*) = 7 FROM t2
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
--source include/stop_slave.inc
|
||||
--replace_result $MASTER_MYPORT MASTER_MYPORT
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT;
|
||||
@ -131,8 +127,7 @@ connection server_3;
|
||||
--replace_result $SLAVE_MYPORT SLAVE_MYPORT
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SLAVE_MYPORT;
|
||||
--source include/start_slave.inc
|
||||
--let $wait_condition= SELECT COUNT(*) = 7 FROM t2
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
connection server_4;
|
||||
--source include/stop_slave.inc
|
||||
@ -142,6 +137,7 @@ eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_3;
|
||||
|
||||
connection server_1;
|
||||
DROP TABLE t1,t2;
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--echo *** A few more checks for BINLOG_GTID_POS function ***
|
||||
--let $valid_binlog_name = query_get_value(SHOW BINARY LOGS,Log_name,1)
|
||||
@ -163,6 +159,7 @@ eval SELECT BINLOG_GTID_POS('$valid_binlog_name',18446744073709551616);
|
||||
|
||||
--echo *** Some tests of @@GLOBAL.gtid_binlog_state ***
|
||||
--connection server_2
|
||||
--source include/sync_with_master_gtid.inc
|
||||
--source include/stop_slave.inc
|
||||
|
||||
--connection server_1
|
||||
@ -192,21 +189,183 @@ SET GLOBAL gtid_binlog_state = @old_state;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||
SET gtid_seq_no=100;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
--let $master_pos= `SELECT @@GLOBAL.gtid_binlog_pos`
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--source include/start_slave.inc
|
||||
# We cannot just use sync_with_master as we've done RESET MASTER, so
|
||||
# slave old-style position is wrong.
|
||||
# So sync on gtid position instead.
|
||||
--let $wait_condition= SELECT @@GLOBAL.gtid_binlog_pos = '$master_pos'
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
SELECT * FROM t1;
|
||||
# Check that the IO gtid position in SHOW SLAVE STATUS is also correct.
|
||||
--let $status_items= Gtid_IO_Pos
|
||||
--source include/show_slave_status.inc
|
||||
|
||||
--echo *** Test @@LAST_GTID and MASTER_GTID_WAIT() ***
|
||||
|
||||
--connection server_1
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
--save_master_pos
|
||||
|
||||
--connection server_2
|
||||
--sync_with_master
|
||||
--source include/stop_slave.inc
|
||||
|
||||
--connect (m1,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
|
||||
SELECT @@last_gtid;
|
||||
SET gtid_seq_no=110;
|
||||
SELECT @@last_gtid;
|
||||
BEGIN;
|
||||
SELECT @@last_gtid;
|
||||
INSERT INTO t1 VALUES (2);
|
||||
SELECT @@last_gtid;
|
||||
COMMIT;
|
||||
SELECT @@last_gtid;
|
||||
--let $pos= `SELECT @@gtid_binlog_pos`
|
||||
|
||||
--connect (s1,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
eval SET @pos= '$pos';
|
||||
# Check NULL argument.
|
||||
SELECT master_gtid_wait(NULL);
|
||||
# Check empty argument returns immediately.
|
||||
SELECT master_gtid_wait('', NULL);
|
||||
# Let's check that we get a timeout
|
||||
SELECT master_gtid_wait(@pos, 0.5);
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
# Now actually wait until the slave reaches the position
|
||||
send SELECT master_gtid_wait(@pos);
|
||||
|
||||
--connection server_2
|
||||
--source include/start_slave.inc
|
||||
|
||||
--connection s1
|
||||
reap;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
# Test waiting on a domain that does not exist yet.
|
||||
--source include/stop_slave.inc
|
||||
|
||||
--connection server_1
|
||||
SET gtid_domain_id= 1;
|
||||
INSERT INTO t1 VALUES (3);
|
||||
--let $pos= `SELECT @@gtid_binlog_pos`
|
||||
|
||||
--connection s1
|
||||
eval SET @pos= '$pos';
|
||||
SELECT master_gtid_wait(@pos, 0);
|
||||
SELECT * FROM t1 WHERE a >= 3;
|
||||
send SELECT master_gtid_wait(@pos, -1);
|
||||
|
||||
--connection server_2
|
||||
--source include/start_slave.inc
|
||||
|
||||
--connection s1
|
||||
reap;
|
||||
SELECT * FROM t1 WHERE a >= 3;
|
||||
# Waiting for only part of the position.
|
||||
SELECT master_gtid_wait('1-1-1', 0);
|
||||
|
||||
# Now test a lot of parallel master_gtid_wait() calls, completing in different
|
||||
# order, and some of which time out or get killed on the way.
|
||||
|
||||
--connection s1
|
||||
send SELECT master_gtid_wait('2-1-1,1-1-4,0-1-110');
|
||||
|
||||
--connect (s2,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
# This will time out.
|
||||
send SELECT master_gtid_wait('0-1-1000', 0.5);
|
||||
|
||||
--connect (s3,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
# This one we will kill
|
||||
--let $kill1_id= `SELECT connection_id()`
|
||||
send SELECT master_gtid_wait('0-1-2000');
|
||||
|
||||
--connect (s4,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
send SELECT master_gtid_wait('2-1-10');
|
||||
|
||||
--connect (s5,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
send SELECT master_gtid_wait('2-1-6', 1);
|
||||
|
||||
# This one we will kill also.
|
||||
--connect (s6,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
--let $kill2_id= `SELECT connection_id()`
|
||||
send SELECT master_gtid_wait('2-1-5');
|
||||
|
||||
--connect (s7,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
send SELECT master_gtid_wait('2-1-10');
|
||||
|
||||
--connect (s8,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
send SELECT master_gtid_wait('2-1-5,1-1-4,0-1-110');
|
||||
|
||||
--connect (s9,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
send SELECT master_gtid_wait('2-1-2');
|
||||
|
||||
--connection server_2
|
||||
# This one completes immediately.
|
||||
SELECT master_gtid_wait('1-1-1');
|
||||
|
||||
--connect (s10,127.0.0.1,root,,test,$SERVER_MYPORT_2,)
|
||||
send SELECT master_gtid_wait('0-1-109');
|
||||
|
||||
--connection server_2
|
||||
# This one should time out.
|
||||
SELECT master_gtid_wait('2-1-2', 0.5);
|
||||
|
||||
--replace_result $kill1_id KILL_ID
|
||||
eval KILL QUERY $kill1_id;
|
||||
--connection s3
|
||||
--error ER_QUERY_INTERRUPTED
|
||||
reap;
|
||||
|
||||
--connection server_1
|
||||
SET gtid_domain_id=2;
|
||||
SET gtid_seq_no=2;
|
||||
INSERT INTO t1 VALUES (4);
|
||||
|
||||
--connection s9
|
||||
reap;
|
||||
|
||||
--connection server_2
|
||||
--replace_result $kill2_id KILL_ID
|
||||
eval KILL CONNECTION $kill2_id;
|
||||
|
||||
--connection s6
|
||||
--error 2013
|
||||
reap;
|
||||
|
||||
--connection server_1
|
||||
SET gtid_domain_id=1;
|
||||
SET gtid_seq_no=4;
|
||||
INSERT INTO t1 VALUES (5);
|
||||
SET gtid_domain_id=2;
|
||||
SET gtid_seq_no=5;
|
||||
INSERT INTO t1 VALUES (6);
|
||||
|
||||
--connection s8
|
||||
reap;
|
||||
--connection s1
|
||||
reap;
|
||||
--connection s2
|
||||
reap;
|
||||
--connection s5
|
||||
reap;
|
||||
--connection s10
|
||||
reap;
|
||||
|
||||
--connection server_1
|
||||
SET gtid_domain_id=2;
|
||||
SET gtid_seq_no=10;
|
||||
INSERT INTO t1 VALUES (7);
|
||||
|
||||
--connection s4
|
||||
reap;
|
||||
--connection s7
|
||||
reap;
|
||||
|
||||
|
||||
--connection server_1
|
||||
DROP TABLE t1;
|
||||
|
||||
|
@ -46,6 +46,7 @@ while ($1)
|
||||
dec $1;
|
||||
}
|
||||
--enable_query_log
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
SET SESSION debug_dbug="+d,crash_dispatch_command_before";
|
||||
--error 2006,2013
|
||||
@ -60,15 +61,14 @@ EOF
|
||||
--source include/wait_until_connected_again.inc
|
||||
|
||||
--connection server_2
|
||||
--let $wait_condition= SELECT COUNT(*) = 200 FROM t1 WHERE b=2
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
--connection server_1
|
||||
INSERT INTO t1 VALUES (1000, 3);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--let $wait_condition= SELECT COUNT(*) = 1 FROM t1 WHERE b=3
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
--connection server_1
|
||||
DROP TABLE t1;
|
||||
@ -141,6 +141,7 @@ START SLAVE;
|
||||
|
||||
--connection server_1
|
||||
INSERT INTO t1 VALUES (4);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--source include/wait_until_disconnected.inc
|
||||
@ -152,8 +153,7 @@ EOF
|
||||
--enable_reconnect
|
||||
--source include/wait_until_connected_again.inc
|
||||
|
||||
--let $wait_condition= SELECT COUNT(*) = 4 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
# Crash the slave just before committing.
|
||||
--source include/stop_slave.inc
|
||||
@ -165,6 +165,7 @@ START SLAVE;
|
||||
|
||||
--connection server_1
|
||||
INSERT INTO t1 VALUES (5);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--source include/wait_until_disconnected.inc
|
||||
@ -176,8 +177,7 @@ EOF
|
||||
--enable_reconnect
|
||||
--source include/wait_until_connected_again.inc
|
||||
|
||||
--let $wait_condition= SELECT COUNT(*) = 5 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
# Crash the slave just after committing.
|
||||
--source include/stop_slave.inc
|
||||
@ -189,6 +189,7 @@ START SLAVE;
|
||||
|
||||
--connection server_1
|
||||
INSERT INTO t1 VALUES (6);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--source include/wait_until_disconnected.inc
|
||||
@ -200,8 +201,7 @@ EOF
|
||||
--enable_reconnect
|
||||
--source include/wait_until_connected_again.inc
|
||||
|
||||
--let $wait_condition= SELECT COUNT(*) = 6 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
# Crash the slave just before updating relay-log.info
|
||||
--source include/stop_slave.inc
|
||||
@ -213,6 +213,7 @@ START SLAVE;
|
||||
|
||||
--connection server_1
|
||||
INSERT INTO t1 VALUES (7);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--source include/wait_until_disconnected.inc
|
||||
@ -224,8 +225,7 @@ EOF
|
||||
--enable_reconnect
|
||||
--source include/wait_until_connected_again.inc
|
||||
|
||||
--let $wait_condition= SELECT COUNT(*) = 7 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
# Crash the slave just after updating relay-log.info
|
||||
--source include/stop_slave.inc
|
||||
@ -237,6 +237,7 @@ START SLAVE;
|
||||
|
||||
--connection server_1
|
||||
INSERT INTO t1 VALUES (8);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--source include/wait_until_disconnected.inc
|
||||
@ -248,8 +249,7 @@ EOF
|
||||
--enable_reconnect
|
||||
--source include/wait_until_connected_again.inc
|
||||
|
||||
--let $wait_condition= SELECT COUNT(*) = 8 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
|
||||
# Check that everything was replicated correctly.
|
||||
|
@ -79,6 +79,7 @@ RESET MASTER;
|
||||
INSERT INTO t1 VALUES (2);
|
||||
# And this will be GTID 0-1-2
|
||||
INSERT INTO t1 VALUES (4);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection slave
|
||||
SET sql_log_bin = 0;
|
||||
@ -110,8 +111,7 @@ RESET MASTER;
|
||||
SET GLOBAL gtid_slave_pos = "0-1-1";
|
||||
|
||||
START SLAVE;
|
||||
--let $wait_condition= SELECT COUNT(*) = 4 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
--echo *** MDEV-4688: Empty value of @@GLOBAL.gtid_slave_pos ***
|
||||
@ -125,6 +125,7 @@ SELECT * FROM t1 ORDER BY a;
|
||||
--connection master
|
||||
# This will be GTID 0-1-3
|
||||
INSERT INTO t1 VALUES (5);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection slave
|
||||
SET @old_dbug= @@GLOBAL.debug_dbug;
|
||||
@ -141,8 +142,7 @@ SELECT @@GLOBAL.gtid_slave_pos;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SET GLOBAL debug_dbug= @old_dbug;
|
||||
START SLAVE SQL_THREAD;
|
||||
--let $wait_condition= SELECT COUNT(*) = 5 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
|
||||
@ -167,10 +167,10 @@ START SLAVE;
|
||||
|
||||
--connection master
|
||||
INSERT INTO t1 VALUES (6);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection slave
|
||||
--let $wait_condition= SELECT COUNT(*) = 6 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
|
||||
|
@ -32,12 +32,12 @@ START SLAVE;
|
||||
--connection server_2
|
||||
INSERT INTO t1 VALUES (3, 2);
|
||||
INSERT INTO t1 VALUES (4, 2);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--source include/show_binlog_events.inc
|
||||
|
||||
--connection server_1
|
||||
--let $wait_condition= SELECT COUNT(*) = 4 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
@ -45,14 +45,14 @@ SELECT * FROM t1 ORDER BY a;
|
||||
RESET SLAVE;
|
||||
INSERT INTO t1 VALUES (5, 1);
|
||||
INSERT INTO t1 VALUES (6, 1);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT,
|
||||
master_use_gtid = current_pos;
|
||||
START SLAVE;
|
||||
--let $wait_condition= SELECT COUNT(*) = 6 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
|
@ -67,6 +67,7 @@ SET sql_log_bin=1;
|
||||
|
||||
--connection server_1
|
||||
INSERT INTO t1 VALUES(3);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
SET GLOBAL gtid_slave_pos='0-1-3';
|
||||
@ -74,13 +75,13 @@ SET GLOBAL gtid_slave_pos='0-1-3';
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT,
|
||||
MASTER_USE_GTID=CURRENT_POS;
|
||||
--source include/start_slave.inc
|
||||
--let $wait_condition= SELECT COUNT(*) = 3 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER by a;
|
||||
--source include/stop_slave.inc
|
||||
|
||||
--connection server_1
|
||||
INSERT INTO t1 VALUES (4);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
# Now add some local transactions that conflict with the GTID position
|
||||
@ -93,8 +94,7 @@ SET GLOBAL gtid_slave_pos='0-1-4';
|
||||
RESET MASTER;
|
||||
SET GLOBAL gtid_slave_pos='0-1-4';
|
||||
START SLAVE;
|
||||
--let $wait_condition= SELECT COUNT(*) = 4 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER by a;
|
||||
|
||||
--connection server_1
|
||||
@ -200,10 +200,10 @@ CHANGE MASTER TO MASTER_USE_GTID=CURRENT_POS;
|
||||
|
||||
--connection server_1
|
||||
INSERT INTO t1 VALUES(3);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--let $wait_condition= SELECT COUNT(*) = 3 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SET SQL_LOG_BIN=0;
|
||||
call mtr.add_suppression("Slave: Table 't1' already exists error.* 1050");
|
||||
@ -215,10 +215,10 @@ SET SQL_LOG_BIN=1;
|
||||
--connection server_1
|
||||
FLUSH LOGS;
|
||||
INSERT INTO t1 VALUES (4);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--let $wait_condition= SELECT COUNT(*) = 4 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
--source include/stop_slave.inc
|
||||
|
||||
--connection server_1
|
||||
@ -228,13 +228,13 @@ FLUSH LOGS;
|
||||
--source include/wait_for_purge.inc
|
||||
--source include/show_binary_logs.inc
|
||||
INSERT INTO t1 VALUES (5);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT;
|
||||
--source include/start_slave.inc
|
||||
--let $wait_condition= SELECT COUNT(*) = 5 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
|
||||
@ -249,11 +249,11 @@ SET GLOBAL gtid_slave_pos="";
|
||||
RESET MASTER;
|
||||
TRUNCATE TABLE t1;
|
||||
INSERT INTO t1 VALUES (10); # Will be GTID 0-1-2
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--source include/start_slave.inc
|
||||
--let $wait_condition= SELECT COUNT(*) = 1 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
SELECT * FROM t1;
|
||||
--let $value= query_get_value(SHOW SLAVE STATUS, "Using_Gtid", 1)
|
||||
|
@ -39,6 +39,7 @@ FLUSH LOGS;
|
||||
INSERT INTO t1 VALUES (2);
|
||||
FLUSH LOGS;
|
||||
INSERT INTO t1 VALUES (3);
|
||||
--source include/save_master_gtid.inc
|
||||
--source include/show_binary_logs.inc
|
||||
|
||||
# Let the slave mysqld server start again.
|
||||
@ -50,8 +51,7 @@ EOF
|
||||
--enable_reconnect
|
||||
--source include/wait_until_connected_again.inc
|
||||
|
||||
--let $wait_condition= SELECT COUNT(*) = 3 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
|
||||
@ -88,10 +88,10 @@ SHOW BINLOG EVENTS IN 'master-bin.000005' LIMIT 1,1;
|
||||
--source include/show_binary_logs.inc
|
||||
|
||||
INSERT INTO t1 VALUES(5);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--let $wait_condition= SELECT COUNT(*) = 5 FROM t1
|
||||
--source include/wait_condition.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
--echo *** Test that @@gtid_slave_pos and @@gtid_current_pos are correctly loaded even if slave threads have not started. ***
|
||||
|
9
mysql-test/suite/sys_vars/r/last_gtid_basic.result
Normal file
9
mysql-test/suite/sys_vars/r/last_gtid_basic.result
Normal file
@ -0,0 +1,9 @@
|
||||
SELECT @@global.last_gtid;
|
||||
ERROR HY000: Variable 'last_gtid' is a SESSION variable
|
||||
SET GLOBAL last_gtid= 10;
|
||||
ERROR HY000: Variable 'last_gtid' is a read only variable
|
||||
SET SESSION last_gtid= 20;
|
||||
ERROR HY000: Variable 'last_gtid' is a read only variable
|
||||
SELECT @@session.last_gtid;
|
||||
@@session.last_gtid
|
||||
|
11
mysql-test/suite/sys_vars/t/last_gtid_basic.test
Normal file
11
mysql-test/suite/sys_vars/t/last_gtid_basic.test
Normal file
@ -0,0 +1,11 @@
|
||||
--source include/not_embedded.inc
|
||||
|
||||
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||
SELECT @@global.last_gtid;
|
||||
|
||||
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||
SET GLOBAL last_gtid= 10;
|
||||
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||
SET SESSION last_gtid= 20;
|
||||
|
||||
SELECT @@session.last_gtid;
|
@ -1783,6 +1783,19 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class Create_func_master_gtid_wait : public Create_native_func
|
||||
{
|
||||
public:
|
||||
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
|
||||
|
||||
static Create_func_master_gtid_wait s_singleton;
|
||||
|
||||
protected:
|
||||
Create_func_master_gtid_wait() {}
|
||||
virtual ~Create_func_master_gtid_wait() {}
|
||||
};
|
||||
|
||||
|
||||
class Create_func_md5 : public Create_func_arg1
|
||||
{
|
||||
public:
|
||||
@ -4590,6 +4603,47 @@ Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name,
|
||||
}
|
||||
|
||||
|
||||
Create_func_master_gtid_wait Create_func_master_gtid_wait::s_singleton;
|
||||
|
||||
Item*
|
||||
Create_func_master_gtid_wait::create_native(THD *thd, LEX_STRING name,
|
||||
List<Item> *item_list)
|
||||
{
|
||||
Item *func= NULL;
|
||||
int arg_count= 0;
|
||||
|
||||
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
|
||||
|
||||
if (item_list != NULL)
|
||||
arg_count= item_list->elements;
|
||||
|
||||
if (arg_count < 1 || arg_count > 2)
|
||||
{
|
||||
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
|
||||
return func;
|
||||
}
|
||||
|
||||
thd->lex->safe_to_cache_query= 0;
|
||||
|
||||
Item *param_1= item_list->pop();
|
||||
switch (arg_count) {
|
||||
case 1:
|
||||
{
|
||||
func= new (thd->mem_root) Item_master_gtid_wait(param_1);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
Item *param_2= item_list->pop();
|
||||
func= new (thd->mem_root) Item_master_gtid_wait(param_1, param_2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
Create_func_md5 Create_func_md5::s_singleton;
|
||||
|
||||
Item*
|
||||
@ -5536,6 +5590,7 @@ static Native_func_registry func_array[] =
|
||||
{ { C_STRING_WITH_LEN("MAKEDATE") }, BUILDER(Create_func_makedate)},
|
||||
{ { C_STRING_WITH_LEN("MAKETIME") }, BUILDER(Create_func_maketime)},
|
||||
{ { C_STRING_WITH_LEN("MAKE_SET") }, BUILDER(Create_func_make_set)},
|
||||
{ { C_STRING_WITH_LEN("MASTER_GTID_WAIT") }, BUILDER(Create_func_master_gtid_wait)},
|
||||
{ { C_STRING_WITH_LEN("MASTER_POS_WAIT") }, BUILDER(Create_func_master_pos_wait)},
|
||||
{ { C_STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_mbr_contains)},
|
||||
{ { C_STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
|
||||
|
@ -3991,6 +3991,34 @@ err:
|
||||
}
|
||||
|
||||
|
||||
longlong Item_master_gtid_wait::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
longlong result= 0;
|
||||
|
||||
if (args[0]->null_value)
|
||||
{
|
||||
null_value= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
null_value=0;
|
||||
#ifdef HAVE_REPLICATION
|
||||
THD* thd= current_thd;
|
||||
longlong timeout_us;
|
||||
String *gtid_pos = args[0]->val_str(&value);
|
||||
|
||||
if (arg_count==2 && !args[1]->null_value)
|
||||
timeout_us= (longlong)(1e6*args[1]->val_real());
|
||||
else
|
||||
timeout_us= (longlong)-1;
|
||||
|
||||
result= rpl_global_gtid_waiting.wait_for_pos(thd, gtid_pos, timeout_us);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Enables a session to wait on a condition until a timeout or a network
|
||||
disconnect occurs.
|
||||
|
@ -1642,6 +1642,22 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class Item_master_gtid_wait :public Item_int_func
|
||||
{
|
||||
String value;
|
||||
public:
|
||||
Item_master_gtid_wait(Item *a) :Item_int_func(a) {}
|
||||
Item_master_gtid_wait(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||
longlong val_int();
|
||||
const char *func_name() const { return "master_gtid_wait"; }
|
||||
void fix_length_and_dec() { max_length=10+1+10+1+20+1; maybe_null=0;}
|
||||
bool check_vcol_func_processor(uchar *int_arg)
|
||||
{
|
||||
return trace_unsupported_by_check_vcol_func_processor(func_name());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* Handling of user definable variables */
|
||||
|
||||
class user_var_entry;
|
||||
|
50
sql/log.cc
50
sql/log.cc
@ -2933,7 +2933,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
|
||||
|
||||
|
||||
MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
|
||||
:reset_master_pending(false),
|
||||
:reset_master_pending(false), mark_xid_done_waiting(0),
|
||||
bytes_written(0), file_id(1), open_count(1),
|
||||
group_commit_queue(0), group_commit_queue_busy(FALSE),
|
||||
num_commits(0), num_group_commits(0),
|
||||
@ -3749,6 +3749,31 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log,
|
||||
const char* save_name;
|
||||
DBUG_ENTER("reset_logs");
|
||||
|
||||
if (!is_relay_log)
|
||||
{
|
||||
if (init_state && !is_empty_state())
|
||||
{
|
||||
my_error(ER_BINLOG_MUST_BE_EMPTY, MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
Mark that a RESET MASTER is in progress.
|
||||
This ensures that a binlog checkpoint will not try to write binlog
|
||||
checkpoint events, which would be useless (as we are deleting the binlog
|
||||
anyway) and could deadlock, as we are holding LOCK_log.
|
||||
|
||||
Wait for any mark_xid_done() calls that might be already running to
|
||||
complete (mark_xid_done_waiting counter to drop to zero); we need to
|
||||
do this before we take the LOCK_log to not deadlock.
|
||||
*/
|
||||
mysql_mutex_lock(&LOCK_xid_list);
|
||||
reset_master_pending= true;
|
||||
while (mark_xid_done_waiting > 0)
|
||||
mysql_cond_wait(&COND_xid_list, &LOCK_xid_list);
|
||||
mysql_mutex_unlock(&LOCK_xid_list);
|
||||
}
|
||||
|
||||
if (thd)
|
||||
ha_reset_logs(thd);
|
||||
/*
|
||||
@ -3760,24 +3785,6 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log,
|
||||
|
||||
if (!is_relay_log)
|
||||
{
|
||||
if (init_state && !is_empty_state())
|
||||
{
|
||||
my_error(ER_BINLOG_MUST_BE_EMPTY, MYF(0));
|
||||
mysql_mutex_unlock(&LOCK_index);
|
||||
mysql_mutex_unlock(&LOCK_log);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
Mark that a RESET MASTER is in progress.
|
||||
This ensures that a binlog checkpoint will not try to write binlog
|
||||
checkpoint events, which would be useless (as we are deleting the binlog
|
||||
anyway) and could deadlock, as we are holding LOCK_log.
|
||||
*/
|
||||
mysql_mutex_lock(&LOCK_xid_list);
|
||||
reset_master_pending= true;
|
||||
mysql_mutex_unlock(&LOCK_xid_list);
|
||||
|
||||
/*
|
||||
We are going to nuke all binary log files.
|
||||
Without binlog, we cannot XA recover prepared-but-not-committed
|
||||
@ -5446,6 +5453,7 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone,
|
||||
}
|
||||
if (err)
|
||||
return true;
|
||||
thd->last_commit_gtid= gtid;
|
||||
|
||||
Gtid_log_event gtid_event(thd, seq_no, domain_id, standalone,
|
||||
LOG_EVENT_SUPPRESS_USE_F, is_transactional,
|
||||
@ -8833,9 +8841,13 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint)
|
||||
locks in the opposite order.
|
||||
*/
|
||||
|
||||
++mark_xid_done_waiting;
|
||||
mysql_mutex_unlock(&LOCK_xid_list);
|
||||
mysql_mutex_lock(&LOCK_log);
|
||||
mysql_mutex_lock(&LOCK_xid_list);
|
||||
--mark_xid_done_waiting;
|
||||
if (unlikely(reset_master_pending))
|
||||
mysql_cond_signal(&COND_xid_list);
|
||||
/* We need to reload current_binlog_id due to release/re-take of lock. */
|
||||
current= current_binlog_id;
|
||||
|
||||
|
@ -471,6 +471,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
|
||||
checkpoint arrives - when all have arrived, RESET MASTER will complete.
|
||||
*/
|
||||
bool reset_master_pending;
|
||||
ulong mark_xid_done_waiting;
|
||||
|
||||
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */
|
||||
mysql_mutex_t LOCK_index;
|
||||
|
@ -780,6 +780,7 @@ PSI_mutex_key key_LOCK_stats,
|
||||
key_LOCK_global_user_client_stats, key_LOCK_global_table_stats,
|
||||
key_LOCK_global_index_stats,
|
||||
key_LOCK_wakeup_ready, key_LOCK_wait_commit;
|
||||
PSI_mutex_key key_LOCK_gtid_waiting;
|
||||
|
||||
PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered;
|
||||
|
||||
@ -825,6 +826,7 @@ static PSI_mutex_info all_server_mutexes[]=
|
||||
{ &key_LOCK_global_index_stats, "LOCK_global_index_stats", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_wakeup_ready, "THD::LOCK_wakeup_ready", 0},
|
||||
{ &key_LOCK_wait_commit, "wait_for_commit::LOCK_wait_commit", 0},
|
||||
{ &key_LOCK_gtid_waiting, "gtid_waiting::LOCK_gtid_waiting", 0},
|
||||
{ &key_LOCK_thd_data, "THD::LOCK_thd_data", 0},
|
||||
{ &key_LOCK_user_conn, "LOCK_user_conn", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_uuid_short_generator, "LOCK_uuid_short_generator", PSI_FLAG_GLOBAL},
|
||||
@ -895,6 +897,7 @@ PSI_cond_key key_RELAYLOG_COND_queue_busy;
|
||||
PSI_cond_key key_TC_LOG_MMAP_COND_queue_busy;
|
||||
PSI_cond_key key_COND_rpl_thread, key_COND_rpl_thread_pool,
|
||||
key_COND_parallel_entry, key_COND_prepare_ordered;
|
||||
PSI_cond_key key_COND_wait_gtid;
|
||||
|
||||
static PSI_cond_info all_server_conds[]=
|
||||
{
|
||||
@ -940,7 +943,8 @@ static PSI_cond_info all_server_conds[]=
|
||||
{ &key_COND_rpl_thread, "COND_rpl_thread", 0},
|
||||
{ &key_COND_rpl_thread_pool, "COND_rpl_thread_pool", 0},
|
||||
{ &key_COND_parallel_entry, "COND_parallel_entry", 0},
|
||||
{ &key_COND_prepare_ordered, "COND_prepare_ordered", 0}
|
||||
{ &key_COND_prepare_ordered, "COND_prepare_ordered", 0},
|
||||
{ &key_COND_wait_gtid, "COND_wait_gtid", 0}
|
||||
};
|
||||
|
||||
PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert,
|
||||
@ -1821,6 +1825,7 @@ static void mysqld_exit(int exit_code)
|
||||
but if a kill -15 signal was sent, the signal thread did
|
||||
spawn the kill_server_thread thread, which is running concurrently.
|
||||
*/
|
||||
rpl_deinit_gtid_waiting();
|
||||
rpl_deinit_gtid_slave_state();
|
||||
wait_for_signal_thread_to_end();
|
||||
mysql_audit_finalize();
|
||||
@ -4202,6 +4207,7 @@ static int init_thread_environment()
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
rpl_init_gtid_slave_state();
|
||||
rpl_init_gtid_waiting();
|
||||
#endif
|
||||
|
||||
DBUG_RETURN(0);
|
||||
|
@ -256,6 +256,7 @@ extern PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state,
|
||||
extern PSI_mutex_key key_LOCK_stats,
|
||||
key_LOCK_global_user_client_stats, key_LOCK_global_table_stats,
|
||||
key_LOCK_global_index_stats, key_LOCK_wakeup_ready, key_LOCK_wait_commit;
|
||||
extern PSI_mutex_key key_LOCK_gtid_waiting;
|
||||
|
||||
extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger,
|
||||
key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave,
|
||||
@ -285,6 +286,7 @@ extern PSI_cond_key key_RELAYLOG_COND_queue_busy;
|
||||
extern PSI_cond_key key_TC_LOG_MMAP_COND_queue_busy;
|
||||
extern PSI_cond_key key_COND_rpl_thread, key_COND_rpl_thread_pool,
|
||||
key_COND_parallel_entry;
|
||||
extern PSI_cond_key key_COND_wait_gtid;
|
||||
|
||||
extern PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert,
|
||||
key_thread_handle_manager, key_thread_kill_server, key_thread_main,
|
||||
|
507
sql/rpl_gtid.cc
507
sql/rpl_gtid.cc
@ -43,9 +43,9 @@ rpl_slave_state::update_state_hash(uint64 sub_id, rpl_gtid *gtid)
|
||||
there will not be an attempt to delete the corresponding table row before
|
||||
it is even committed.
|
||||
*/
|
||||
lock();
|
||||
mysql_mutex_lock(&LOCK_slave_state);
|
||||
err= update(gtid->domain_id, gtid->server_id, sub_id, gtid->seq_no);
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
if (err)
|
||||
{
|
||||
sql_print_warning("Slave: Out of memory during slave state maintenance. "
|
||||
@ -82,11 +82,20 @@ rpl_slave_state::record_and_update_gtid(THD *thd, rpl_group_info *rgi)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
rpl_slave_state_free_element(void *arg)
|
||||
{
|
||||
struct rpl_slave_state::element *elem= (struct rpl_slave_state::element *)arg;
|
||||
mysql_cond_destroy(&elem->COND_wait_gtid);
|
||||
my_free(elem);
|
||||
}
|
||||
|
||||
|
||||
rpl_slave_state::rpl_slave_state()
|
||||
: last_sub_id(0), inited(false), loaded(false)
|
||||
{
|
||||
my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id),
|
||||
sizeof(uint32), NULL, my_free, HASH_UNIQUE);
|
||||
sizeof(uint32), NULL, rpl_slave_state_free_element, HASH_UNIQUE);
|
||||
}
|
||||
|
||||
|
||||
@ -146,6 +155,21 @@ rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id,
|
||||
if (!(elem= get_element(domain_id)))
|
||||
return 1;
|
||||
|
||||
if (seq_no > elem->highest_seq_no)
|
||||
elem->highest_seq_no= seq_no;
|
||||
if (elem->gtid_waiter && elem->min_wait_seq_no <= seq_no)
|
||||
{
|
||||
/*
|
||||
Someone was waiting in MASTER_GTID_WAIT() for this GTID to appear.
|
||||
Signal (and remove) them. The waiter will handle all the processing
|
||||
of all pending MASTER_GTID_WAIT(), so we do not slow down the
|
||||
replication SQL thread.
|
||||
*/
|
||||
mysql_mutex_assert_owner(&LOCK_slave_state);
|
||||
elem->gtid_waiter= NULL;
|
||||
mysql_cond_broadcast(&elem->COND_wait_gtid);
|
||||
}
|
||||
|
||||
if (!(list_elem= (list_element *)my_malloc(sizeof(*list_elem), MYF(MY_WME))))
|
||||
return 1;
|
||||
list_elem->server_id= server_id;
|
||||
@ -173,6 +197,9 @@ rpl_slave_state::get_element(uint32 domain_id)
|
||||
return NULL;
|
||||
elem->list= NULL;
|
||||
elem->domain_id= domain_id;
|
||||
elem->highest_seq_no= 0;
|
||||
elem->gtid_waiter= NULL;
|
||||
mysql_cond_init(key_COND_wait_gtid, &elem->COND_wait_gtid, 0);
|
||||
if (my_hash_insert(&hash, (uchar *)elem))
|
||||
{
|
||||
my_free(elem);
|
||||
@ -378,10 +405,10 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
||||
goto end;
|
||||
}
|
||||
|
||||
lock();
|
||||
mysql_mutex_lock(&LOCK_slave_state);
|
||||
if ((elem= get_element(gtid->domain_id)) == NULL)
|
||||
{
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||
err= 1;
|
||||
goto end;
|
||||
@ -410,7 +437,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
||||
cur->next= NULL;
|
||||
elem->list= cur;
|
||||
}
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
|
||||
if (!elist)
|
||||
goto end;
|
||||
@ -470,9 +497,9 @@ end:
|
||||
*/
|
||||
if (elist)
|
||||
{
|
||||
lock();
|
||||
mysql_mutex_lock(&LOCK_slave_state);
|
||||
put_back_list(gtid->domain_id, elist);
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
}
|
||||
|
||||
ha_rollback_trans(thd, FALSE);
|
||||
@ -499,9 +526,9 @@ rpl_slave_state::next_sub_id(uint32 domain_id)
|
||||
{
|
||||
uint64 sub_id= 0;
|
||||
|
||||
lock();
|
||||
mysql_mutex_lock(&LOCK_slave_state);
|
||||
sub_id= ++last_sub_id;
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
|
||||
return sub_id;
|
||||
}
|
||||
@ -541,7 +568,7 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data,
|
||||
my_hash_insert(>id_hash, (uchar *)(&extra_gtids[i])))
|
||||
goto err;
|
||||
|
||||
lock();
|
||||
mysql_mutex_lock(&LOCK_slave_state);
|
||||
|
||||
for (i= 0; i < hash.records; ++i)
|
||||
{
|
||||
@ -576,19 +603,19 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data,
|
||||
memcpy(&best_gtid, gtid, sizeof(best_gtid));
|
||||
if (my_hash_delete(>id_hash, rec))
|
||||
{
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if ((res= (*cb)(&best_gtid, data)))
|
||||
{
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
|
||||
/* Also add any remaining extra domain_ids. */
|
||||
for (i= 0; i < gtid_hash.records; ++i)
|
||||
@ -659,11 +686,11 @@ rpl_slave_state::domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid)
|
||||
list_element *list;
|
||||
uint64 best_sub_id;
|
||||
|
||||
lock();
|
||||
mysql_mutex_lock(&LOCK_slave_state);
|
||||
elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0);
|
||||
if (!elem || !(list= elem->list))
|
||||
{
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -681,7 +708,7 @@ rpl_slave_state::domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid)
|
||||
out_gtid->seq_no= list->seq_no;
|
||||
}
|
||||
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -811,7 +838,7 @@ rpl_slave_state::is_empty()
|
||||
uint32 i;
|
||||
bool result= true;
|
||||
|
||||
lock();
|
||||
mysql_mutex_lock(&LOCK_slave_state);
|
||||
for (i= 0; i < hash.records; ++i)
|
||||
{
|
||||
element *e= (element *)my_hash_element(&hash, i);
|
||||
@ -821,7 +848,7 @@ rpl_slave_state::is_empty()
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
mysql_mutex_unlock(&LOCK_slave_state);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1647,3 +1674,445 @@ slave_connection_state::get_gtid_list(rpl_gtid *gtid_list, uint32 list_size)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Execute a MASTER_GTID_WAIT().
|
||||
The position to wait for is in gtid_str in string form.
|
||||
The timeout in microseconds is in timeout_us, zero means no timeout.
|
||||
|
||||
Returns:
|
||||
1 for error.
|
||||
0 for wait completed.
|
||||
-1 for wait timed out.
|
||||
*/
|
||||
int
|
||||
gtid_waiting::wait_for_pos(THD *thd, String *gtid_str, longlong timeout_us)
|
||||
{
|
||||
int err;
|
||||
rpl_gtid *wait_pos;
|
||||
uint32 count, i;
|
||||
struct timespec wait_until, *wait_until_ptr;
|
||||
|
||||
/* Wait for the empty position returns immediately. */
|
||||
if (gtid_str->length() == 0)
|
||||
return 0;
|
||||
|
||||
if (!(wait_pos= gtid_parse_string_to_list(gtid_str->ptr(), gtid_str->length(),
|
||||
&count)))
|
||||
{
|
||||
my_error(ER_INCORRECT_GTID_STATE, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (timeout_us >= 0)
|
||||
{
|
||||
set_timespec_nsec(wait_until, (ulonglong)1000*timeout_us);
|
||||
wait_until_ptr= &wait_until;
|
||||
}
|
||||
else
|
||||
wait_until_ptr= NULL;
|
||||
err= 0;
|
||||
for (i= 0; i < count; ++i)
|
||||
{
|
||||
if ((err= wait_for_gtid(thd, &wait_pos[i], wait_until_ptr)))
|
||||
break;
|
||||
}
|
||||
my_free(wait_pos);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gtid_waiting::promote_new_waiter(gtid_waiting::hash_element *he)
|
||||
{
|
||||
queue_element *qe;
|
||||
|
||||
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
||||
if (queue_empty(&he->queue))
|
||||
return;
|
||||
qe= (queue_element *)queue_top(&he->queue);
|
||||
qe->do_small_wait= true;
|
||||
mysql_cond_signal(&qe->thd->COND_wakeup_ready);
|
||||
}
|
||||
|
||||
void
|
||||
gtid_waiting::process_wait_hash(uint64 wakeup_seq_no,
|
||||
gtid_waiting::hash_element *he)
|
||||
{
|
||||
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
queue_element *qe;
|
||||
|
||||
if (queue_empty(&he->queue))
|
||||
break;
|
||||
qe= (queue_element *)queue_top(&he->queue);
|
||||
if (qe->wait_seq_no > wakeup_seq_no)
|
||||
break;
|
||||
DBUG_ASSERT(!qe->done);
|
||||
queue_remove_top(&he->queue);
|
||||
qe->done= true;;
|
||||
mysql_cond_signal(&qe->thd->COND_wakeup_ready);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Execute a MASTER_GTID_WAIT() for one specific domain.
|
||||
|
||||
The implementation is optimised primarily for (1) minimal performance impact
|
||||
on the slave replication threads, and secondarily for (2) quick performance
|
||||
of MASTER_GTID_WAIT() on a single GTID, which can be useful for consistent
|
||||
read to clients in an async replication read-scaleout scenario.
|
||||
|
||||
To achieve (1), we have a "small" wait and a "large" wait. The small wait
|
||||
contends with the replication threads on the lock on the gtid_slave_pos, so
|
||||
only minimal processing is done under that lock, and only a single waiter at
|
||||
a time does the small wait.
|
||||
|
||||
If there is already a small waiter, a new thread will either replace the
|
||||
small waiter (if it needs to wait for an earlier sequence number), or
|
||||
instead do a "large" wait.
|
||||
|
||||
Once awoken on the small wait, the waiting thread releases the lock shared
|
||||
with the SQL threads quickly, and then processes all waiters currently doing
|
||||
the large wait using a different lock that does not impact replication.
|
||||
|
||||
This way, the SQL threads only need to do a single check + possibly a
|
||||
pthread_cond_signal() when updating the gtid_slave_state, and the time that
|
||||
non-SQL threads contend for the lock on gtid_slave_state is minimized.
|
||||
|
||||
There is always at least one thread that has the responsibility to ensure
|
||||
that there is a small waiter; this thread has queue_element::do_small_wait
|
||||
set to true. This thread will do the small wait until it is done, at which
|
||||
point it will make sure to pass on the responsibility to another thread.
|
||||
Normally only one thread has do_small_wait==true, but it can occasionally
|
||||
happen that there is more than one, when threads race one another for the
|
||||
lock on the small wait (this results in slightly increased activity on the
|
||||
small lock but is otherwise harmless).
|
||||
|
||||
Returns:
|
||||
0 Wait completed normally
|
||||
-1 Wait completed due to timeout
|
||||
1 An error (my_error() will have been called to set the error in the da)
|
||||
*/
|
||||
int
|
||||
gtid_waiting::wait_for_gtid(THD *thd, rpl_gtid *wait_gtid,
|
||||
struct timespec *wait_until)
|
||||
{
|
||||
bool timed_out= false;
|
||||
#ifdef HAVE_REPLICATION
|
||||
queue_element elem;
|
||||
uint32 domain_id= wait_gtid->domain_id;
|
||||
uint64 seq_no= wait_gtid->seq_no;
|
||||
hash_element *he;
|
||||
rpl_slave_state::element *slave_state_elem= NULL;
|
||||
const char *old_msg= NULL;
|
||||
bool did_enter_cond= false;
|
||||
|
||||
elem.wait_seq_no= seq_no;
|
||||
elem.thd= thd;
|
||||
elem.done= false;
|
||||
|
||||
mysql_mutex_lock(&LOCK_gtid_waiting);
|
||||
if (!(he= get_entry(wait_gtid->domain_id)))
|
||||
{
|
||||
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
If there is already another waiter with seq_no no larger than our own,
|
||||
we are sure that there is already a small waiter that will wake us up
|
||||
(or later pass the small wait responsibility to us). So in this case, we
|
||||
do not need to touch the small wait lock at all.
|
||||
*/
|
||||
elem.do_small_wait=
|
||||
(queue_empty(&he->queue) ||
|
||||
((queue_element *)queue_top(&he->queue))->wait_seq_no > seq_no);
|
||||
|
||||
if (register_in_wait_queue(thd, wait_gtid, he, &elem))
|
||||
{
|
||||
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
Loop, doing either the small or large wait as appropriate, until either
|
||||
the position waited for is reached, or we get a kill or timeout.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
||||
|
||||
if (elem.do_small_wait)
|
||||
{
|
||||
uint64 wakeup_seq_no;
|
||||
queue_element *cur_waiter;
|
||||
|
||||
mysql_mutex_lock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
/*
|
||||
The elements in the gtid_slave_state_hash are never re-allocated once
|
||||
they enter the hash, so we do not need to re-do the lookup after releasing
|
||||
and re-aquiring the lock.
|
||||
*/
|
||||
if (!slave_state_elem &&
|
||||
!(slave_state_elem= rpl_global_gtid_slave_state.get_element(domain_id)))
|
||||
{
|
||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
remove_from_wait_queue(he, &elem);
|
||||
promote_new_waiter(he);
|
||||
if (did_enter_cond)
|
||||
thd->exit_cond(old_msg);
|
||||
else
|
||||
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((wakeup_seq_no= slave_state_elem->highest_seq_no) >= seq_no)
|
||||
{
|
||||
/*
|
||||
We do not have to wait. (We will be removed from the wait queue when
|
||||
we call process_wait_hash() below.
|
||||
*/
|
||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
}
|
||||
else if ((cur_waiter= slave_state_elem->gtid_waiter) &&
|
||||
slave_state_elem->min_wait_seq_no <= seq_no)
|
||||
{
|
||||
/*
|
||||
There is already a suitable small waiter, go do the large wait.
|
||||
(Normally we would not have needed to check the small wait in this
|
||||
case, but it can happen if we race with another thread for the small
|
||||
lock).
|
||||
*/
|
||||
elem.do_small_wait= false;
|
||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
We have to do the small wait ourselves (stealing it from any thread
|
||||
that might already be waiting for a later seq_no).
|
||||
*/
|
||||
slave_state_elem->gtid_waiter= &elem;
|
||||
slave_state_elem->min_wait_seq_no= seq_no;
|
||||
if (cur_waiter)
|
||||
{
|
||||
/* We stole the wait, so wake up the old waiting thread. */
|
||||
mysql_cond_signal(&slave_state_elem->COND_wait_gtid);
|
||||
}
|
||||
|
||||
/* Release the large lock, and do the small wait. */
|
||||
if (did_enter_cond)
|
||||
{
|
||||
thd->exit_cond(old_msg);
|
||||
did_enter_cond= false;
|
||||
}
|
||||
else
|
||||
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
||||
old_msg=
|
||||
thd->enter_cond(&slave_state_elem->COND_wait_gtid,
|
||||
&rpl_global_gtid_slave_state.LOCK_slave_state,
|
||||
"Waiting in MASTER_GTID_WAIT() (primary waiter)");
|
||||
do
|
||||
{
|
||||
if (thd->check_killed())
|
||||
break;
|
||||
else if (wait_until)
|
||||
{
|
||||
int err=
|
||||
mysql_cond_timedwait(&slave_state_elem->COND_wait_gtid,
|
||||
&rpl_global_gtid_slave_state.LOCK_slave_state,
|
||||
wait_until);
|
||||
if (err == ETIMEDOUT || err == ETIME)
|
||||
{
|
||||
timed_out= true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
mysql_cond_wait(&slave_state_elem->COND_wait_gtid,
|
||||
&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
} while (slave_state_elem->gtid_waiter == &elem);
|
||||
wakeup_seq_no= slave_state_elem->highest_seq_no;
|
||||
/*
|
||||
If we aborted due to timeout or kill, remove us as waiter.
|
||||
|
||||
If we were replaced by another waiter with a smaller seq_no, then we
|
||||
no longer have responsibility for the small wait.
|
||||
*/
|
||||
if ((cur_waiter= slave_state_elem->gtid_waiter))
|
||||
{
|
||||
if (cur_waiter == &elem)
|
||||
slave_state_elem->gtid_waiter= NULL;
|
||||
else if (slave_state_elem->min_wait_seq_no <= seq_no)
|
||||
elem.do_small_wait= false;
|
||||
}
|
||||
thd->exit_cond(old_msg);
|
||||
|
||||
mysql_mutex_lock(&LOCK_gtid_waiting);
|
||||
}
|
||||
|
||||
/*
|
||||
Note that hash_entry pointers do not change once allocated, so we do
|
||||
not need to lookup `he' again after re-aquiring LOCK_gtid_waiting.
|
||||
*/
|
||||
process_wait_hash(wakeup_seq_no, he);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Do the large wait. */
|
||||
if (!did_enter_cond)
|
||||
{
|
||||
old_msg= thd->enter_cond(&thd->COND_wakeup_ready, &LOCK_gtid_waiting,
|
||||
"Waiting in MASTER_GTID_WAIT()");
|
||||
did_enter_cond= true;
|
||||
}
|
||||
while (!elem.done && !thd->check_killed())
|
||||
{
|
||||
thd_wait_begin(thd, THD_WAIT_BINLOG);
|
||||
if (wait_until)
|
||||
{
|
||||
int err= mysql_cond_timedwait(&thd->COND_wakeup_ready,
|
||||
&LOCK_gtid_waiting, wait_until);
|
||||
if (err == ETIMEDOUT || err == ETIME)
|
||||
timed_out= true;
|
||||
}
|
||||
else
|
||||
mysql_cond_wait(&thd->COND_wakeup_ready, &LOCK_gtid_waiting);
|
||||
thd_wait_end(thd);
|
||||
if (elem.do_small_wait || timed_out)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((thd->killed || timed_out) && !elem.done)
|
||||
{
|
||||
/* Aborted, so remove ourselves from the hash. */
|
||||
remove_from_wait_queue(he, &elem);
|
||||
elem.done= true;
|
||||
}
|
||||
if (elem.done)
|
||||
{
|
||||
/*
|
||||
If our wait is done, but we have (or were passed) responsibility for
|
||||
the small wait, then we need to pass on that task to someone else.
|
||||
*/
|
||||
if (elem.do_small_wait)
|
||||
promote_new_waiter(he);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (did_enter_cond)
|
||||
thd->exit_cond(old_msg);
|
||||
else
|
||||
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
||||
if (thd->killed)
|
||||
thd->send_kill_message();
|
||||
#endif /* HAVE_REPLICATION */
|
||||
return timed_out ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_hash_element(void *p)
|
||||
{
|
||||
gtid_waiting::hash_element *e= (gtid_waiting::hash_element *)p;
|
||||
delete_queue(&e->queue);
|
||||
my_free(e);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gtid_waiting::init()
|
||||
{
|
||||
my_hash_init(&hash, &my_charset_bin, 32,
|
||||
offsetof(hash_element, domain_id), sizeof(uint32), NULL,
|
||||
free_hash_element, HASH_UNIQUE);
|
||||
mysql_mutex_init(key_LOCK_gtid_waiting, &LOCK_gtid_waiting, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gtid_waiting::destroy()
|
||||
{
|
||||
mysql_mutex_destroy(&LOCK_gtid_waiting);
|
||||
my_hash_free(&hash);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmp_queue_elem(void *, uchar *a, uchar *b)
|
||||
{
|
||||
uint64 seq_no_a= *(uint64 *)a;
|
||||
uint64 seq_no_b= *(uint64 *)b;
|
||||
if (seq_no_a < seq_no_b)
|
||||
return -1;
|
||||
else if (seq_no_a == seq_no_b)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
gtid_waiting::hash_element *
|
||||
gtid_waiting::get_entry(uint32 domain_id)
|
||||
{
|
||||
hash_element *e;
|
||||
|
||||
if ((e= (hash_element *)my_hash_search(&hash, (const uchar *)&domain_id, 0)))
|
||||
return e;
|
||||
|
||||
if (!(e= (hash_element *)my_malloc(sizeof(*e), MYF(MY_WME))))
|
||||
{
|
||||
my_error(ER_OUTOFMEMORY, MYF(0), sizeof(*e));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (init_queue(&e->queue, 8, offsetof(queue_element, wait_seq_no), 0,
|
||||
cmp_queue_elem, NULL, 1+offsetof(queue_element, queue_idx), 1))
|
||||
{
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||
my_free(e);
|
||||
return NULL;
|
||||
}
|
||||
e->domain_id= domain_id;
|
||||
if (my_hash_insert(&hash, (uchar *)e))
|
||||
{
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||
delete_queue(&e->queue);
|
||||
my_free(e);
|
||||
return NULL;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gtid_waiting::register_in_wait_queue(THD *thd, rpl_gtid *wait_gtid,
|
||||
gtid_waiting::hash_element *he,
|
||||
gtid_waiting::queue_element *elem)
|
||||
{
|
||||
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
||||
|
||||
if (queue_insert_safe(&he->queue, (uchar *)elem))
|
||||
{
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gtid_waiting::remove_from_wait_queue(gtid_waiting::hash_element *he,
|
||||
gtid_waiting::queue_element *elem)
|
||||
{
|
||||
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
||||
|
||||
queue_remove(&he->queue, elem->queue_idx);
|
||||
}
|
||||
|
@ -16,6 +16,10 @@
|
||||
#ifndef RPL_GTID_H
|
||||
#define RPL_GTID_H
|
||||
|
||||
#include "hash.h"
|
||||
#include "queues.h"
|
||||
|
||||
|
||||
/* Definitions for MariaDB global transaction ID (GTID). */
|
||||
|
||||
|
||||
@ -36,6 +40,57 @@ enum enum_gtid_skip_type {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Structure to keep track of threads waiting in MASTER_GTID_WAIT().
|
||||
|
||||
Since replication is (mostly) single-threaded, we want to minimise the
|
||||
performance impact on that from MASTER_GTID_WAIT(). To achieve this, we
|
||||
are careful to keep the common lock between replication threads and
|
||||
MASTER_GTID_WAIT threads held for as short as possible. We keep only
|
||||
a single thread waiting to be notified by the replication threads; this
|
||||
thread then handles all the (potentially heavy) lifting of dealing with
|
||||
all current waiting threads.
|
||||
*/
|
||||
struct gtid_waiting {
|
||||
/* Elements in the hash, basically a priority queue for each domain. */
|
||||
struct hash_element {
|
||||
QUEUE queue;
|
||||
uint32 domain_id;
|
||||
};
|
||||
/* A priority queue to handle waiters in one domain in seq_no order. */
|
||||
struct queue_element {
|
||||
uint64 wait_seq_no;
|
||||
THD *thd;
|
||||
int queue_idx;
|
||||
/*
|
||||
do_small_wait is true if we have responsibility for ensuring that there
|
||||
is a small waiter.
|
||||
*/
|
||||
bool do_small_wait;
|
||||
/*
|
||||
The flag `done' is set when the wait is completed (either due to reaching
|
||||
the position waited for, or due to timeout or kill). The queue_element
|
||||
is in the queue if and only if `done' is true.
|
||||
*/
|
||||
bool done;
|
||||
};
|
||||
|
||||
mysql_mutex_t LOCK_gtid_waiting;
|
||||
HASH hash;
|
||||
|
||||
void init();
|
||||
void destroy();
|
||||
hash_element *get_entry(uint32 domain_id);
|
||||
int wait_for_pos(THD *thd, String *gtid_str, longlong timeout_us);
|
||||
void promote_new_waiter(gtid_waiting::hash_element *he);
|
||||
int wait_for_gtid(THD *thd, rpl_gtid *wait_gtid, struct timespec *wait_until);
|
||||
void process_wait_hash(uint64 wakeup_seq_no, gtid_waiting::hash_element *he);
|
||||
int register_in_wait_queue(THD *thd, rpl_gtid *wait_gtid, hash_element *he,
|
||||
queue_element *elem);
|
||||
void remove_from_wait_queue(hash_element *he, queue_element *elem);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Replication slave state.
|
||||
|
||||
@ -61,6 +116,20 @@ struct rpl_slave_state
|
||||
{
|
||||
struct list_element *list;
|
||||
uint32 domain_id;
|
||||
/* Highest seq_no seen so far in this domain. */
|
||||
uint64 highest_seq_no;
|
||||
/*
|
||||
If this is non-NULL, then it is the waiter responsible for the small
|
||||
wait in MASTER_GTID_WAIT().
|
||||
*/
|
||||
gtid_waiting::queue_element *gtid_waiter;
|
||||
/*
|
||||
If gtid_waiter is non-NULL, then this is the seq_no that its
|
||||
MASTER_GTID_WAIT() is waiting on. When we reach this seq_no, we need to
|
||||
signal the waiter on COND_wait_gtid.
|
||||
*/
|
||||
uint64 min_wait_seq_no;
|
||||
mysql_cond_t COND_wait_gtid;
|
||||
|
||||
list_element *grab_list() { list_element *l= list; list= NULL; return l; }
|
||||
void add(list_element *l)
|
||||
@ -99,9 +168,6 @@ struct rpl_slave_state
|
||||
bool in_statement);
|
||||
bool is_empty();
|
||||
|
||||
void lock() { DBUG_ASSERT(inited); mysql_mutex_lock(&LOCK_slave_state); }
|
||||
void unlock() { DBUG_ASSERT(inited); mysql_mutex_unlock(&LOCK_slave_state); }
|
||||
|
||||
element *get_element(uint32 domain_id);
|
||||
int put_back_list(uint32 domain_id, list_element *list);
|
||||
|
||||
@ -204,6 +270,7 @@ struct slave_connection_state
|
||||
int get_gtid_list(rpl_gtid *gtid_list, uint32 list_size);
|
||||
};
|
||||
|
||||
|
||||
extern bool rpl_slave_state_tostring_helper(String *dest, const rpl_gtid *gtid,
|
||||
bool *first);
|
||||
extern int gtid_check_rpl_slave_state_table(TABLE *table);
|
||||
|
@ -37,6 +37,8 @@ static int count_relay_log_space(Relay_log_info* rli);
|
||||
domain).
|
||||
*/
|
||||
rpl_slave_state rpl_global_gtid_slave_state;
|
||||
/* Object used for MASTER_GTID_WAIT(). */
|
||||
gtid_waiting rpl_global_gtid_waiting;
|
||||
|
||||
|
||||
// Defined in slave.cc
|
||||
@ -1317,9 +1319,9 @@ rpl_load_gtid_slave_state(THD *thd)
|
||||
uint32 i;
|
||||
DBUG_ENTER("rpl_load_gtid_slave_state");
|
||||
|
||||
rpl_global_gtid_slave_state.lock();
|
||||
mysql_mutex_lock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
bool loaded= rpl_global_gtid_slave_state.loaded;
|
||||
rpl_global_gtid_slave_state.unlock();
|
||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
if (loaded)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
@ -1419,10 +1421,10 @@ rpl_load_gtid_slave_state(THD *thd)
|
||||
}
|
||||
}
|
||||
|
||||
rpl_global_gtid_slave_state.lock();
|
||||
mysql_mutex_lock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
if (rpl_global_gtid_slave_state.loaded)
|
||||
{
|
||||
rpl_global_gtid_slave_state.unlock();
|
||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -1434,7 +1436,7 @@ rpl_load_gtid_slave_state(THD *thd)
|
||||
tmp_entry.sub_id,
|
||||
tmp_entry.gtid.seq_no)))
|
||||
{
|
||||
rpl_global_gtid_slave_state.unlock();
|
||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||
goto end;
|
||||
}
|
||||
@ -1447,14 +1449,14 @@ rpl_load_gtid_slave_state(THD *thd)
|
||||
mysql_bin_log.bump_seq_no_counter_if_needed(entry->gtid.domain_id,
|
||||
entry->gtid.seq_no))
|
||||
{
|
||||
rpl_global_gtid_slave_state.unlock();
|
||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
rpl_global_gtid_slave_state.loaded= true;
|
||||
rpl_global_gtid_slave_state.unlock();
|
||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state.LOCK_slave_state);
|
||||
|
||||
err= 0; /* Clear HA_ERR_END_OF_FILE */
|
||||
|
||||
|
@ -708,6 +708,7 @@ int init_relay_log_info(Relay_log_info* rli, const char* info_fname);
|
||||
|
||||
|
||||
extern struct rpl_slave_state rpl_global_gtid_slave_state;
|
||||
extern gtid_waiting rpl_global_gtid_waiting;
|
||||
|
||||
int rpl_load_gtid_slave_state(THD *thd);
|
||||
int event_group_new_gtid(rpl_group_info *rgi, Gtid_log_event *gev);
|
||||
|
@ -6524,7 +6524,7 @@ ER_UNTIL_REQUIRES_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"
|
||||
eng "The binlog on the master is missing the GTID %u-%u-%llu requested by the slave (even though a subsequent sequence number does exist), and GTID strict mode is enabled"
|
||||
ER_SLAVE_UNEXPECTED_MASTER_SWITCH
|
||||
eng "Unexpected GTID received from master after reconnect. This normally indicates that the master server was replaced without restarting the slave threads. %s"
|
||||
ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO
|
||||
|
@ -1267,6 +1267,7 @@ void THD::init(void)
|
||||
set_status_var_init();
|
||||
bzero((char *) &org_status_var, sizeof(org_status_var));
|
||||
start_bytes_received= 0;
|
||||
last_commit_gtid.seq_no= 0;
|
||||
|
||||
if (variables.sql_log_bin)
|
||||
variables.option_bits|= OPTION_BIN_LOG;
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA,
|
||||
THR_LOCK_INFO */
|
||||
#include "my_apc.h"
|
||||
#include "rpl_gtid.h"
|
||||
|
||||
class Reprepare_observer;
|
||||
class Relay_log_info;
|
||||
@ -3410,6 +3411,12 @@ private:
|
||||
*/
|
||||
LEX_STRING invoker_user;
|
||||
LEX_STRING invoker_host;
|
||||
|
||||
/* Protect against add/delete of temporary tables in parallel replication */
|
||||
void rgi_lock_temporary_tables();
|
||||
void rgi_unlock_temporary_tables();
|
||||
bool rgi_have_temporary_tables();
|
||||
public:
|
||||
/*
|
||||
Flag, mutex and condition for a thread to wait for a signal from another
|
||||
thread.
|
||||
@ -3420,12 +3427,12 @@ private:
|
||||
bool wakeup_ready;
|
||||
mysql_mutex_t LOCK_wakeup_ready;
|
||||
mysql_cond_t COND_wakeup_ready;
|
||||
/*
|
||||
The GTID assigned to the last commit. If no GTID was assigned to any commit
|
||||
so far, this is indicated by last_commit_gtid.seq_no == 0.
|
||||
*/
|
||||
rpl_gtid last_commit_gtid;
|
||||
|
||||
/* Protect against add/delete of temporary tables in parallel replication */
|
||||
void rgi_lock_temporary_tables();
|
||||
void rgi_unlock_temporary_tables();
|
||||
bool rgi_have_temporary_tables();
|
||||
public:
|
||||
inline void lock_temporary_tables()
|
||||
{
|
||||
if (rgi_slave)
|
||||
|
@ -3965,6 +3965,20 @@ rpl_deinit_gtid_slave_state()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rpl_init_gtid_waiting()
|
||||
{
|
||||
rpl_global_gtid_waiting.init();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rpl_deinit_gtid_waiting()
|
||||
{
|
||||
rpl_global_gtid_waiting.destroy();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Format the current GTID state as a string, for returning the value of
|
||||
@@global.gtid_slave_pos.
|
||||
|
@ -70,6 +70,8 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
|
||||
extern PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state;
|
||||
void rpl_init_gtid_slave_state();
|
||||
void rpl_deinit_gtid_slave_state();
|
||||
void rpl_init_gtid_waiting();
|
||||
void rpl_deinit_gtid_waiting();
|
||||
int gtid_state_from_binlog_pos(const char *name, uint32 pos, String *out_str);
|
||||
int rpl_append_gtid_state(String *dest, bool use_binlog);
|
||||
int rpl_load_gtid_state(slave_connection_state *state, bool use_binlog);
|
||||
|
@ -1538,6 +1538,33 @@ static Sys_var_gtid_binlog_state Sys_gtid_binlog_state(
|
||||
GLOBAL_VAR(opt_gtid_binlog_state_dummy), NO_CMD_LINE);
|
||||
|
||||
|
||||
static Sys_var_last_gtid Sys_last_gtid(
|
||||
"last_gtid", "The GTID of the last commit (if binlogging was enabled), "
|
||||
"or the empty string if none.",
|
||||
READ_ONLY sys_var::ONLY_SESSION, NO_CMD_LINE);
|
||||
|
||||
|
||||
uchar *
|
||||
Sys_var_last_gtid::session_value_ptr(THD *thd, LEX_STRING *base)
|
||||
{
|
||||
char buf[10+1+10+1+20+1];
|
||||
String str(buf, sizeof(buf), system_charset_info);
|
||||
char *p;
|
||||
bool first= true;
|
||||
|
||||
str.length(0);
|
||||
if ((thd->last_commit_gtid.seq_no > 0 &&
|
||||
rpl_slave_state_tostring_helper(&str, &thd->last_commit_gtid, &first)) ||
|
||||
!(p= thd->strmake(str.ptr(), str.length())))
|
||||
{
|
||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (uchar *)p;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
check_slave_parallel_threads(sys_var *self, THD *thd, set_var *var)
|
||||
{
|
||||
|
@ -2211,3 +2211,53 @@ public:
|
||||
}
|
||||
uchar *global_value_ptr(THD *thd, LEX_STRING *base);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Class for @@session.last_gtid.
|
||||
*/
|
||||
class Sys_var_last_gtid: public sys_var
|
||||
{
|
||||
public:
|
||||
Sys_var_last_gtid(const char *name_arg,
|
||||
const char *comment, int flag_args, CMD_LINE getopt)
|
||||
: sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
|
||||
getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
|
||||
NULL, NULL, NULL)
|
||||
{
|
||||
option.var_type= GET_STR;
|
||||
}
|
||||
bool do_check(THD *thd, set_var *var)
|
||||
{
|
||||
DBUG_ASSERT(false);
|
||||
return true;
|
||||
}
|
||||
bool session_update(THD *thd, set_var *var)
|
||||
{
|
||||
DBUG_ASSERT(false);
|
||||
return true;
|
||||
}
|
||||
bool global_update(THD *thd, set_var *var)
|
||||
{
|
||||
DBUG_ASSERT(false);
|
||||
return true;
|
||||
}
|
||||
bool check_update_type(Item_result type) {
|
||||
DBUG_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
void session_save_default(THD *thd, set_var *var)
|
||||
{
|
||||
DBUG_ASSERT(false);
|
||||
}
|
||||
void global_save_default(THD *thd, set_var *var)
|
||||
{
|
||||
DBUG_ASSERT(false);
|
||||
}
|
||||
uchar *session_value_ptr(THD *thd, LEX_STRING *base);
|
||||
uchar *global_value_ptr(THD *thd, LEX_STRING *base)
|
||||
{
|
||||
DBUG_ASSERT(false);
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user