MDEV-12179: Per-engine mysql.gtid_slave_pos table
Merge into MariaDB 10.3.
This commit is contained in:
commit
1d91910b94
@ -46,6 +46,9 @@ BEGIN;
|
|||||||
SELECT * FROM t1 FOR UPDATE;
|
SELECT * FROM t1 FOR UPDATE;
|
||||||
# Save variable 'Slave_retried_transactions' before deadlock
|
# Save variable 'Slave_retried_transactions' before deadlock
|
||||||
let $slave_retried_transactions= query_get_value(SHOW GLOBAL STATUS LIKE 'Slave_retried_transactions', Value, 1);
|
let $slave_retried_transactions= query_get_value(SHOW GLOBAL STATUS LIKE 'Slave_retried_transactions', Value, 1);
|
||||||
|
# Run the START SLAVE in a separate connection. Otherwise it terminates
|
||||||
|
# the SELECT FOR UPDATE transaction (START SLAVE does implicit COMMIT!).
|
||||||
|
connection slave1;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
# Wait until SQL thread blocked: variable 'Slave_retried_transactions' will incremented
|
# Wait until SQL thread blocked: variable 'Slave_retried_transactions' will incremented
|
||||||
let $status_var= Slave_retried_transactions;
|
let $status_var= Slave_retried_transactions;
|
||||||
@ -53,6 +56,7 @@ let $status_var_value= $slave_retried_transactions;
|
|||||||
let $status_type= GLOBAL;
|
let $status_type= GLOBAL;
|
||||||
let $status_var_comparsion= >;
|
let $status_var_comparsion= >;
|
||||||
--source include/wait_for_status_var.inc
|
--source include/wait_for_status_var.inc
|
||||||
|
connection slave;
|
||||||
SELECT COUNT(*) FROM t2;
|
SELECT COUNT(*) FROM t2;
|
||||||
COMMIT;
|
COMMIT;
|
||||||
sync_with_master;
|
sync_with_master;
|
||||||
@ -78,9 +82,11 @@ BEGIN;
|
|||||||
# Hold lock
|
# Hold lock
|
||||||
SELECT * FROM t1 FOR UPDATE;
|
SELECT * FROM t1 FOR UPDATE;
|
||||||
# Wait until slave stopped with error 'Lock wait timeout exceeded'
|
# Wait until slave stopped with error 'Lock wait timeout exceeded'
|
||||||
|
connection slave1;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
let $slave_sql_errno= 1205;
|
let $slave_sql_errno= 1205;
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
connection slave;
|
||||||
SELECT COUNT(*) FROM t2;
|
SELECT COUNT(*) FROM t2;
|
||||||
COMMIT;
|
COMMIT;
|
||||||
--source include/start_slave.inc
|
--source include/start_slave.inc
|
||||||
@ -109,9 +115,11 @@ BEGIN;
|
|||||||
# Hold lock
|
# Hold lock
|
||||||
SELECT * FROM t1 FOR UPDATE;
|
SELECT * FROM t1 FOR UPDATE;
|
||||||
# Wait until slave stopped with error 'Lock wait timeout exceeded'
|
# Wait until slave stopped with error 'Lock wait timeout exceeded'
|
||||||
|
connection slave1;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
let $slave_sql_errno= 1205;
|
let $slave_sql_errno= 1205;
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
connection slave;
|
||||||
SELECT COUNT(*) FROM t2;
|
SELECT COUNT(*) FROM t2;
|
||||||
COMMIT;
|
COMMIT;
|
||||||
--source include/start_slave.inc
|
--source include/start_slave.inc
|
||||||
|
@ -5225,6 +5225,7 @@ sub server_need_restart {
|
|||||||
if (!My::Options::same($started_opts, $extra_opts) ||
|
if (!My::Options::same($started_opts, $extra_opts) ||
|
||||||
exists $server->{'restart_opts'})
|
exists $server->{'restart_opts'})
|
||||||
{
|
{
|
||||||
|
delete $server->{'restart_opts'};
|
||||||
my $use_dynamic_option_switch= 0;
|
my $use_dynamic_option_switch= 0;
|
||||||
if (!$use_dynamic_option_switch)
|
if (!$use_dynamic_option_switch)
|
||||||
{
|
{
|
||||||
|
@ -257,6 +257,13 @@ The following options may be given as the first argument:
|
|||||||
applied; this means it is the responsibility of the user
|
applied; this means it is the responsibility of the user
|
||||||
to ensure that GTID sequence numbers are strictly
|
to ensure that GTID sequence numbers are strictly
|
||||||
increasing.
|
increasing.
|
||||||
|
--gtid-pos-auto-engines=name
|
||||||
|
List of engines for which to automatically create a
|
||||||
|
mysql.gtid_slave_pos_ENGINE table, if a transaction using
|
||||||
|
that engine is replicated. This can be used to avoid
|
||||||
|
introducing cross-engine transactions, if engines are
|
||||||
|
used different from that used by table
|
||||||
|
mysql.gtid_slave_pos
|
||||||
--gtid-strict-mode Enforce strict seq_no ordering of events in the binary
|
--gtid-strict-mode Enforce strict seq_no ordering of events in the binary
|
||||||
log. Slave stops with an error if it encounters an event
|
log. Slave stops with an error if it encounters an event
|
||||||
that would cause it to generate an out-of-order binlog if
|
that would cause it to generate an out-of-order binlog if
|
||||||
@ -1259,6 +1266,7 @@ getopt-prefix-matching TRUE
|
|||||||
group-concat-max-len 1048576
|
group-concat-max-len 1048576
|
||||||
gtid-domain-id 0
|
gtid-domain-id 0
|
||||||
gtid-ignore-duplicates FALSE
|
gtid-ignore-duplicates FALSE
|
||||||
|
gtid-pos-auto-engines
|
||||||
gtid-strict-mode FALSE
|
gtid-strict-mode FALSE
|
||||||
help TRUE
|
help TRUE
|
||||||
histogram-size 0
|
histogram-size 0
|
||||||
|
@ -65,6 +65,7 @@ include/wait_for_slave_to_start.inc
|
|||||||
set default_master_connection = '';
|
set default_master_connection = '';
|
||||||
connection server_1;
|
connection server_1;
|
||||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||||
|
CALL mtr.add_suppression("This change will not take full effect until all SQL threads have been restarted");
|
||||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
BEGIN;
|
BEGIN;
|
||||||
@ -491,17 +492,21 @@ SET GLOBAL slave_parallel_threads= @old_parallel;
|
|||||||
SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates;
|
SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates;
|
||||||
connection server_1;
|
connection server_1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
include/reset_master_slave.inc
|
include/reset_master_slave.inc
|
||||||
disconnect server_1;
|
disconnect server_1;
|
||||||
connection server_2;
|
connection server_2;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
include/reset_master_slave.inc
|
include/reset_master_slave.inc
|
||||||
disconnect server_2;
|
disconnect server_2;
|
||||||
connection server_3;
|
connection server_3;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
include/reset_master_slave.inc
|
include/reset_master_slave.inc
|
||||||
disconnect server_3;
|
disconnect server_3;
|
||||||
connection server_4;
|
connection server_4;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
include/reset_master_slave.inc
|
include/reset_master_slave.inc
|
||||||
disconnect server_4;
|
disconnect server_4;
|
||||||
|
@ -86,6 +86,7 @@ set default_master_connection = '';
|
|||||||
|
|
||||||
--connection server_1
|
--connection server_1
|
||||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||||
|
CALL mtr.add_suppression("This change will not take full effect until all SQL threads have been restarted");
|
||||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
BEGIN;
|
BEGIN;
|
||||||
@ -431,20 +432,24 @@ SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates;
|
|||||||
|
|
||||||
--connection server_1
|
--connection server_1
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
--source include/reset_master_slave.inc
|
--source include/reset_master_slave.inc
|
||||||
--disconnect server_1
|
--disconnect server_1
|
||||||
|
|
||||||
--connection server_2
|
--connection server_2
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
--source include/reset_master_slave.inc
|
--source include/reset_master_slave.inc
|
||||||
--disconnect server_2
|
--disconnect server_2
|
||||||
|
|
||||||
--connection server_3
|
--connection server_3
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
--source include/reset_master_slave.inc
|
--source include/reset_master_slave.inc
|
||||||
--disconnect server_3
|
--disconnect server_3
|
||||||
|
|
||||||
--connection server_4
|
--connection server_4
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
--source include/reset_master_slave.inc
|
--source include/reset_master_slave.inc
|
||||||
--disconnect server_4
|
--disconnect server_4
|
||||||
|
155
mysql-test/suite/multi_source/gtid_slave_pos.result
Normal file
155
mysql-test/suite/multi_source/gtid_slave_pos.result
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
connect slave1,127.0.0.1,root,,,$SERVER_MYPORT_3;
|
||||||
|
connect master1,127.0.0.1,root,,,$SERVER_MYPORT_1;
|
||||||
|
connect master2,127.0.0.1,root,,,$SERVER_MYPORT_2;
|
||||||
|
connection slave1;
|
||||||
|
CHANGE MASTER 'slave1' TO master_port=MYPORT_1, master_host='127.0.0.1', master_user='root', master_use_gtid=slave_pos;
|
||||||
|
CHANGE MASTER 'slave2' TO master_port=MYPORT_2, master_host='127.0.0.1', master_user='root', master_use_gtid=slave_pos;
|
||||||
|
set default_master_connection = 'slave1';
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_to_start.inc
|
||||||
|
set default_master_connection = 'slave2';
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_to_start.inc
|
||||||
|
set default_master_connection = '';
|
||||||
|
connection master1;
|
||||||
|
SET GLOBAL gtid_domain_id= 1;
|
||||||
|
SET SESSION gtid_domain_id= 1;
|
||||||
|
CREATE TABLE t3 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10));
|
||||||
|
INSERT INTO t1 VALUES (1, "initial");
|
||||||
|
INSERT INTO t3 VALUES (101, "initial 1");
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection master2;
|
||||||
|
SET GLOBAL gtid_domain_id= 2;
|
||||||
|
SET SESSION gtid_domain_id= 2;
|
||||||
|
CREATE TABLE t2 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t2 VALUES (1, "initial");
|
||||||
|
connection slave1;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
connection master2;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave1;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
*** Add an innodb gtid_slave_pos table. It is not used yet as slaves are already running ***
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_innodb LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_innodb ENGINE=InnoDB;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
connection master1;
|
||||||
|
INSERT INTO t3 VALUES (102, "secondary");
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave1;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
domain_id max(seq_no)
|
||||||
|
1 5
|
||||||
|
2 2
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos_innodb GROUP BY domain_id;
|
||||||
|
domain_id max(seq_no)
|
||||||
|
*** Restart one slave thread, the other keeps running. Now the new table is used ***
|
||||||
|
connection slave1;
|
||||||
|
set default_master_connection = 'slave1';
|
||||||
|
STOP SLAVE;
|
||||||
|
include/wait_for_slave_to_stop.inc
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_to_start.inc
|
||||||
|
connection master1;
|
||||||
|
INSERT INTO t1 VALUES (2, "followup");
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave1;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
connection master2;
|
||||||
|
INSERT INTO t2 VALUES (2, "secondary2");
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave1;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
domain_id max(seq_no)
|
||||||
|
1 6
|
||||||
|
2 2
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos_innodb GROUP BY domain_id;
|
||||||
|
domain_id max(seq_no)
|
||||||
|
2 3
|
||||||
|
*** Remove a gtid_slave_posXXX table, restart one slave ***
|
||||||
|
*** Get a warning that the change is not yet picked up ***
|
||||||
|
*** See that updates fail due to trying to use the missing table ***
|
||||||
|
connection slave1;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_innodb;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
set default_master_connection = 'slave2';
|
||||||
|
STOP SLAVE;
|
||||||
|
include/wait_for_slave_to_stop.inc
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_to_start.inc
|
||||||
|
CALL mtr.add_suppression("The table mysql.gtid_slave_pos_innodb was removed.");
|
||||||
|
connection master2;
|
||||||
|
INSERT INTO t2 VALUES (3, "tertiary 2");
|
||||||
|
connection slave1;
|
||||||
|
include/wait_for_slave_sql_error.inc [errno=1942]
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
domain_id max(seq_no)
|
||||||
|
1 6
|
||||||
|
2 2
|
||||||
|
*** Stop both slaves, see that the drop of mysql.gtid_slave_pos_innodb is now picked up ***
|
||||||
|
connection slave1;
|
||||||
|
set default_master_connection = 'slave1';
|
||||||
|
STOP SLAVE;
|
||||||
|
include/wait_for_slave_to_stop.inc
|
||||||
|
set default_master_connection = 'slave2';
|
||||||
|
STOP SLAVE;
|
||||||
|
include/wait_for_slave_to_stop.inc
|
||||||
|
set default_master_connection = 'slave1';
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_to_start.inc
|
||||||
|
connection master1;
|
||||||
|
INSERT INTO t1 VALUES (3, "more stuff");
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave1;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
set default_master_connection = 'slave2';
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_to_start.inc
|
||||||
|
connection master2;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave1;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a b
|
||||||
|
1 initial
|
||||||
|
2 followup
|
||||||
|
3 more stuff
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a b
|
||||||
|
1 initial
|
||||||
|
2 secondary2
|
||||||
|
3 tertiary 2
|
||||||
|
SELECT * FROM t3 ORDER BY a;
|
||||||
|
a b
|
||||||
|
101 initial 1
|
||||||
|
102 secondary
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
domain_id max(seq_no)
|
||||||
|
1 7
|
||||||
|
2 4
|
||||||
|
connection master1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t3;
|
||||||
|
connection master2;
|
||||||
|
DROP TABLE t2;
|
||||||
|
connection slave1;
|
||||||
|
SET GLOBAL gtid_domain_id=0;
|
||||||
|
STOP ALL SLAVES;
|
||||||
|
Warnings:
|
||||||
|
Note 1938 SLAVE 'slave1' stopped
|
||||||
|
Note 1938 SLAVE 'slave2' stopped
|
||||||
|
include/reset_master_slave.inc
|
||||||
|
disconnect slave1;
|
||||||
|
connection master1;
|
||||||
|
SET GLOBAL gtid_domain_id=0;
|
||||||
|
include/reset_master_slave.inc
|
||||||
|
disconnect master1;
|
||||||
|
connection master2;
|
||||||
|
SET GLOBAL gtid_domain_id=0;
|
||||||
|
include/reset_master_slave.inc
|
||||||
|
disconnect master2;
|
173
mysql-test/suite/multi_source/gtid_slave_pos.test
Normal file
173
mysql-test/suite/multi_source/gtid_slave_pos.test
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
--source include/not_embedded.inc
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test multiple mysql.gtid_slave_posXXX tables with multiple master connections
|
||||||
|
#
|
||||||
|
|
||||||
|
--connect (slave1,127.0.0.1,root,,,$SERVER_MYPORT_3)
|
||||||
|
--connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1)
|
||||||
|
--connect (master2,127.0.0.1,root,,,$SERVER_MYPORT_2)
|
||||||
|
|
||||||
|
--connection slave1
|
||||||
|
--replace_result $SERVER_MYPORT_1 MYPORT_1
|
||||||
|
eval CHANGE MASTER 'slave1' TO master_port=$SERVER_MYPORT_1, master_host='127.0.0.1', master_user='root', master_use_gtid=slave_pos;
|
||||||
|
--replace_result $SERVER_MYPORT_2 MYPORT_2
|
||||||
|
eval CHANGE MASTER 'slave2' TO master_port=$SERVER_MYPORT_2, master_host='127.0.0.1', master_user='root', master_use_gtid=slave_pos;
|
||||||
|
set default_master_connection = 'slave1';
|
||||||
|
START SLAVE;
|
||||||
|
--source include/wait_for_slave_to_start.inc
|
||||||
|
set default_master_connection = 'slave2';
|
||||||
|
START SLAVE;
|
||||||
|
--source include/wait_for_slave_to_start.inc
|
||||||
|
set default_master_connection = '';
|
||||||
|
|
||||||
|
|
||||||
|
--connection master1
|
||||||
|
SET GLOBAL gtid_domain_id= 1;
|
||||||
|
SET SESSION gtid_domain_id= 1;
|
||||||
|
CREATE TABLE t3 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10));
|
||||||
|
INSERT INTO t1 VALUES (1, "initial");
|
||||||
|
INSERT INTO t3 VALUES (101, "initial 1");
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection master2
|
||||||
|
SET GLOBAL gtid_domain_id= 2;
|
||||||
|
SET SESSION gtid_domain_id= 2;
|
||||||
|
CREATE TABLE t2 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t2 VALUES (1, "initial");
|
||||||
|
|
||||||
|
|
||||||
|
--connection slave1
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
|
||||||
|
--connection master2
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection slave1
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo *** Add an innodb gtid_slave_pos table. It is not used yet as slaves are already running ***
|
||||||
|
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_innodb LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_innodb ENGINE=InnoDB;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
|
||||||
|
--connection master1
|
||||||
|
INSERT INTO t3 VALUES (102, "secondary");
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection slave1
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos_innodb GROUP BY domain_id;
|
||||||
|
|
||||||
|
--echo *** Restart one slave thread, the other keeps running. Now the new table is used ***
|
||||||
|
--connection slave1
|
||||||
|
set default_master_connection = 'slave1';
|
||||||
|
STOP SLAVE;
|
||||||
|
--source include/wait_for_slave_to_stop.inc
|
||||||
|
START SLAVE;
|
||||||
|
--source include/wait_for_slave_to_start.inc
|
||||||
|
|
||||||
|
# Send through a transaction on the slave1 connection, to be sure that it has
|
||||||
|
# had time to update the state with the new table.
|
||||||
|
--connection master1
|
||||||
|
INSERT INTO t1 VALUES (2, "followup");
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
--connection slave1
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
|
||||||
|
--connection master2
|
||||||
|
INSERT INTO t2 VALUES (2, "secondary2");
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection slave1
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos_innodb GROUP BY domain_id;
|
||||||
|
|
||||||
|
--echo *** Remove a gtid_slave_posXXX table, restart one slave ***
|
||||||
|
--echo *** Get a warning that the change is not yet picked up ***
|
||||||
|
--echo *** See that updates fail due to trying to use the missing table ***
|
||||||
|
--connection slave1
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_innodb;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
set default_master_connection = 'slave2';
|
||||||
|
STOP SLAVE;
|
||||||
|
--source include/wait_for_slave_to_stop.inc
|
||||||
|
START SLAVE;
|
||||||
|
--source include/wait_for_slave_to_start.inc
|
||||||
|
CALL mtr.add_suppression("The table mysql.gtid_slave_pos_innodb was removed.");
|
||||||
|
|
||||||
|
--connection master2
|
||||||
|
INSERT INTO t2 VALUES (3, "tertiary 2");
|
||||||
|
|
||||||
|
--connection slave1
|
||||||
|
--let $slave_sql_errno= 1942
|
||||||
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
|
||||||
|
--echo *** Stop both slaves, see that the drop of mysql.gtid_slave_pos_innodb is now picked up ***
|
||||||
|
--connection slave1
|
||||||
|
set default_master_connection = 'slave1';
|
||||||
|
STOP SLAVE;
|
||||||
|
--source include/wait_for_slave_to_stop.inc
|
||||||
|
set default_master_connection = 'slave2';
|
||||||
|
STOP SLAVE;
|
||||||
|
--source include/wait_for_slave_to_stop.inc
|
||||||
|
set default_master_connection = 'slave1';
|
||||||
|
START SLAVE;
|
||||||
|
--source include/wait_for_slave_to_start.inc
|
||||||
|
# Send through a transaction on the slave1 connection, to be sure that it has
|
||||||
|
# had time to update the state with the new table.
|
||||||
|
--connection master1
|
||||||
|
INSERT INTO t1 VALUES (3, "more stuff");
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
--connection slave1
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
set default_master_connection = 'slave2';
|
||||||
|
START SLAVE;
|
||||||
|
--source include/wait_for_slave_to_start.inc
|
||||||
|
|
||||||
|
--connection master2
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
--connection slave1
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
SELECT * FROM t3 ORDER BY a;
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
--connection master1
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t3;
|
||||||
|
|
||||||
|
--connection master2
|
||||||
|
DROP TABLE t2;
|
||||||
|
|
||||||
|
--connection slave1
|
||||||
|
SET GLOBAL gtid_domain_id=0;
|
||||||
|
--let $wait_condition= SELECT COUNT(*)=0 FROM information_schema.tables WHERE table_name IN ("t1", "t2", "t3") AND table_schema = "test"
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
--sorted_result
|
||||||
|
STOP ALL SLAVES;
|
||||||
|
--source include/reset_master_slave.inc
|
||||||
|
--disconnect slave1
|
||||||
|
|
||||||
|
|
||||||
|
--connection master1
|
||||||
|
SET GLOBAL gtid_domain_id=0;
|
||||||
|
--source include/reset_master_slave.inc
|
||||||
|
--disconnect master1
|
||||||
|
|
||||||
|
--connection master2
|
||||||
|
SET GLOBAL gtid_domain_id=0;
|
||||||
|
--source include/reset_master_slave.inc
|
||||||
|
--disconnect master2
|
@ -39,7 +39,9 @@ connection slave;
|
|||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT * FROM t1 FOR UPDATE;
|
SELECT * FROM t1 FOR UPDATE;
|
||||||
a
|
a
|
||||||
|
connection slave1;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
|
connection slave;
|
||||||
SELECT COUNT(*) FROM t2;
|
SELECT COUNT(*) FROM t2;
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
0
|
0
|
||||||
@ -61,8 +63,10 @@ BEGIN;
|
|||||||
SELECT * FROM t1 FOR UPDATE;
|
SELECT * FROM t1 FOR UPDATE;
|
||||||
a
|
a
|
||||||
1
|
1
|
||||||
|
connection slave1;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1205]
|
include/wait_for_slave_sql_error.inc [errno=1205]
|
||||||
|
connection slave;
|
||||||
SELECT COUNT(*) FROM t2;
|
SELECT COUNT(*) FROM t2;
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
0
|
0
|
||||||
@ -92,8 +96,10 @@ SELECT * FROM t1 FOR UPDATE;
|
|||||||
a
|
a
|
||||||
1
|
1
|
||||||
1
|
1
|
||||||
|
connection slave1;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1205]
|
include/wait_for_slave_sql_error.inc [errno=1205]
|
||||||
|
connection slave;
|
||||||
SELECT COUNT(*) FROM t2;
|
SELECT COUNT(*) FROM t2;
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
0
|
0
|
||||||
|
@ -88,16 +88,16 @@ include/save_master_gtid.inc
|
|||||||
connection server_2;
|
connection server_2;
|
||||||
include/sync_with_master_gtid.inc
|
include/sync_with_master_gtid.inc
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
SET GLOBAL debug_dbug="+d,crash_commit_before";
|
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
|
SET GLOBAL debug_dbug="+d,crash_commit_before";
|
||||||
connection server_1;
|
connection server_1;
|
||||||
INSERT INTO t1 VALUES (5);
|
INSERT INTO t1 VALUES (5);
|
||||||
include/save_master_gtid.inc
|
include/save_master_gtid.inc
|
||||||
connection server_2;
|
connection server_2;
|
||||||
include/sync_with_master_gtid.inc
|
include/sync_with_master_gtid.inc
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
SET GLOBAL debug_dbug="+d,crash_commit_after";
|
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
|
SET GLOBAL debug_dbug="+d,crash_commit_after";
|
||||||
connection server_1;
|
connection server_1;
|
||||||
INSERT INTO t1 VALUES (6);
|
INSERT INTO t1 VALUES (6);
|
||||||
include/save_master_gtid.inc
|
include/save_master_gtid.inc
|
||||||
|
@ -12,21 +12,21 @@ connection master;
|
|||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
connection slave;
|
connection slave;
|
||||||
CALL mtr.add_suppression("Slave: Failed to open mysql.gtid_slave_pos");
|
CALL mtr.add_suppression("Slave: Failed to open mysql.gtid_slave_pos");
|
||||||
include/wait_for_slave_sql_error.inc [errno=1942]
|
include/wait_for_slave_sql_error.inc [errno=1944]
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
ALTER TABLE mysql.gtid_slave_pos CHANGE seq_no seq_no BIGINT UNSIGNED NOT NULL;
|
ALTER TABLE mysql.gtid_slave_pos CHANGE seq_no seq_no BIGINT UNSIGNED NOT NULL;
|
||||||
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
||||||
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id, domain_id);
|
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id, domain_id);
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1942]
|
include/wait_for_slave_sql_error.inc [errno=1944]
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1942]
|
include/wait_for_slave_sql_error.inc [errno=1944]
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id);
|
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id);
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1942]
|
include/wait_for_slave_sql_error.inc [errno=1944]
|
||||||
include/stop_slave.inc
|
include/stop_slave.inc
|
||||||
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
||||||
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (domain_id, sub_id);
|
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (domain_id, sub_id);
|
||||||
|
@ -79,6 +79,7 @@ a
|
|||||||
9
|
9
|
||||||
connection server_1;
|
connection server_1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
|
SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
|
||||||
SET debug_sync = "reset";
|
SET debug_sync = "reset";
|
||||||
connection server_2;
|
connection server_2;
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
include/master-slave.inc
|
include/master-slave.inc
|
||||||
[connection master]
|
[connection master]
|
||||||
|
connection slave;
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
connection master;
|
||||||
CREATE TABLE t1 (i int) ENGINE=InnoDB;
|
CREATE TABLE t1 (i int) ENGINE=InnoDB;
|
||||||
connection slave;
|
connection slave;
|
||||||
*** MDEV-4484, incorrect error handling when entries in gtid_slave_pos not found. ***
|
*** MDEV-4484, incorrect error handling when entries in gtid_slave_pos not found. ***
|
||||||
@ -13,7 +20,6 @@ SET @old_dbug= @@GLOBAL.debug_dbug;
|
|||||||
SET GLOBAL debug_dbug="+d,gtid_slave_pos_simulate_failed_delete";
|
SET GLOBAL debug_dbug="+d,gtid_slave_pos_simulate_failed_delete";
|
||||||
SET sql_log_bin= 0;
|
SET sql_log_bin= 0;
|
||||||
CALL mtr.add_suppression("Can't find file");
|
CALL mtr.add_suppression("Can't find file");
|
||||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
|
||||||
SET sql_log_bin= 1;
|
SET sql_log_bin= 1;
|
||||||
include/start_slave.inc
|
include/start_slave.inc
|
||||||
connection master;
|
connection master;
|
||||||
|
@ -194,7 +194,7 @@ domain_id COUNT(*)
|
|||||||
*** MDEV-4650: show variables; ERROR 1946 (HY000): Failed to load replication slave GTID position ***
|
*** MDEV-4650: show variables; ERROR 1946 (HY000): Failed to load replication slave GTID position ***
|
||||||
connection server_2;
|
connection server_2;
|
||||||
SET sql_log_bin=0;
|
SET sql_log_bin=0;
|
||||||
RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_old;
|
RENAME TABLE mysql.gtid_slave_pos TO mysql.old_gtid_slave_pos;
|
||||||
SET sql_log_bin=1;
|
SET sql_log_bin=1;
|
||||||
SHOW VARIABLES;
|
SHOW VARIABLES;
|
||||||
SHOW VARIABLES LIKE 'gtid_slave_pos';
|
SHOW VARIABLES LIKE 'gtid_slave_pos';
|
||||||
@ -207,7 +207,7 @@ Level Code Message
|
|||||||
Error 1146 Table 'mysql.gtid_slave_pos' doesn't exist
|
Error 1146 Table 'mysql.gtid_slave_pos' doesn't exist
|
||||||
Error 1946 Failed to load replication slave GTID position from table mysql.gtid_slave_pos
|
Error 1946 Failed to load replication slave GTID position from table mysql.gtid_slave_pos
|
||||||
SET sql_log_bin=0;
|
SET sql_log_bin=0;
|
||||||
RENAME TABLE mysql.gtid_slave_pos_old TO mysql.gtid_slave_pos;
|
RENAME TABLE mysql.old_gtid_slave_pos TO mysql.gtid_slave_pos;
|
||||||
CALL mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos");
|
CALL mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos");
|
||||||
SET sql_log_bin=1;
|
SET sql_log_bin=1;
|
||||||
SHOW VARIABLES LIKE 'gtid_slave_pos';
|
SHOW VARIABLES LIKE 'gtid_slave_pos';
|
||||||
|
@ -10,6 +10,8 @@ SET s= SUBSTR(s FROM 1 FOR LOCATE(",", s) - 1);
|
|||||||
RETURN s;
|
RETURN s;
|
||||||
END|
|
END|
|
||||||
connection server_2;
|
connection server_2;
|
||||||
|
include/stop_slave.inc
|
||||||
|
include/start_slave.inc
|
||||||
START SLAVE UNTIL master_gtid_pos = "";
|
START SLAVE UNTIL master_gtid_pos = "";
|
||||||
ERROR HY000: Slave is already running
|
ERROR HY000: Slave is already running
|
||||||
include/stop_slave_io.inc
|
include/stop_slave_io.inc
|
||||||
|
@ -46,5 +46,6 @@ SET GLOBAL slave_parallel_threads=@old_parallel_threads;
|
|||||||
SET GLOBAL max_relay_log_size= @old_max_relay;
|
SET GLOBAL max_relay_log_size= @old_max_relay;
|
||||||
include/start_slave.inc
|
include/start_slave.inc
|
||||||
connection server_1;
|
connection server_1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
include/rpl_end.inc
|
include/rpl_end.inc
|
||||||
|
265
mysql-test/suite/rpl/r/rpl_mdev12179.result
Normal file
265
mysql-test/suite/rpl/r/rpl_mdev12179.result
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
include/rpl_init.inc [topology=1->2]
|
||||||
|
connection server_2;
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb";
|
||||||
|
ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first
|
||||||
|
include/stop_slave.inc
|
||||||
|
CHANGE MASTER TO master_use_gtid=slave_pos;
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
@@gtid_pos_auto_engines
|
||||||
|
|
||||||
|
SELECT @@SESSION.gtid_pos_auto_engines;
|
||||||
|
ERROR HY000: Variable 'gtid_pos_auto_engines' is a GLOBAL variable
|
||||||
|
SET GLOBAL gtid_pos_auto_engines= NULL;
|
||||||
|
ERROR 42000: Variable 'gtid_pos_auto_engines' can't be set to the value of 'NULL'
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
@@gtid_pos_auto_engines
|
||||||
|
InnoDB
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="myisam,innodb";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
@@gtid_pos_auto_engines
|
||||||
|
MyISAM,InnoDB
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb,myisam";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
@@gtid_pos_auto_engines
|
||||||
|
InnoDB,MyISAM
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb,innodb,myisam,innodb,myisam,myisam,innodb";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
@@gtid_pos_auto_engines
|
||||||
|
InnoDB,MyISAM
|
||||||
|
SET GLOBAL gtid_pos_auto_engines=DEFAULT;
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
@@gtid_pos_auto_engines
|
||||||
|
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
@@gtid_pos_auto_engines
|
||||||
|
|
||||||
|
include/start_slave.inc
|
||||||
|
connection server_1;
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
connection server_2;
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_innodb LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_innodb ENGINE=InnoDB;
|
||||||
|
INSERT INTO mysql.gtid_slave_pos_innodb SELECT * FROM mysql.gtid_slave_pos;
|
||||||
|
TRUNCATE mysql.gtid_slave_pos;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t1 VALUES (2);
|
||||||
|
INSERT INTO t1 VALUES (3);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
*** Restart server with --gtid-pos-auto-engines=innodb,myisam ***
|
||||||
|
connection server_2;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
*** Verify no new gtid_slave_pos* tables are created ***
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
table_name engine
|
||||||
|
gtid_slave_pos MyISAM
|
||||||
|
gtid_slave_pos_innodb InnoDB
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
@@gtid_pos_auto_engines
|
||||||
|
InnoDB,MyISAM
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
INSERT INTO mysql.gtid_slave_pos_innodb SELECT * FROM mysql.gtid_slave_pos;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos;
|
||||||
|
RENAME TABLE mysql.gtid_slave_pos_innodb TO mysql.gtid_slave_pos;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
connection server_1;
|
||||||
|
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES (4);
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
*** Restart server with --gtid-pos-auto-engines=myisam,innodb ***
|
||||||
|
connection server_2;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
*** Verify that no new gtid_slave_pos* tables are auto-created ***
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
table_name engine
|
||||||
|
gtid_slave_pos InnoDB
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t1 VALUES (5);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection server_2;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
*** Verify that mysql.gtid_slave_pos_InnoDB is auto-created ***
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
table_name engine
|
||||||
|
gtid_slave_pos MyISAM
|
||||||
|
gtid_slave_pos_InnoDB InnoDB
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
INSERT INTO mysql.gtid_slave_pos SELECT * FROM mysql.gtid_slave_pos_InnoDB;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_InnoDB;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t1 VALUES (6);
|
||||||
|
INSERT INTO t2 VALUES (3);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
*** Restart server without --gtid-pos-auto-engines ***
|
||||||
|
connection server_2;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
*** Verify that no mysql.gtid_slave_pos* table is auto-created ***
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
table_name engine
|
||||||
|
gtid_slave_pos MyISAM
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
domain_id max(seq_no)
|
||||||
|
0 11
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb";
|
||||||
|
include/start_slave.inc
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t1 VALUES (7);
|
||||||
|
INSERT INTO t2 VALUES (4);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection server_2;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
*** Verify that mysql.gtid_slave_pos_InnoDB is auto-created ***
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
table_name engine
|
||||||
|
gtid_slave_pos MyISAM
|
||||||
|
gtid_slave_pos_InnoDB InnoDB
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
domain_id max(seq_no)
|
||||||
|
0 13
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="";
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_InnoDB;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
connection server_1;
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
include/rpl_end.inc
|
@ -3,6 +3,7 @@ include/master-slave.inc
|
|||||||
call mtr.add_suppression("Master is configured to log replication events");
|
call mtr.add_suppression("Master is configured to log replication events");
|
||||||
connection slave;
|
connection slave;
|
||||||
connection slave;
|
connection slave;
|
||||||
|
include/wait_for_slave_to_stop.inc
|
||||||
start slave;
|
start slave;
|
||||||
connection master;
|
connection master;
|
||||||
include/rpl_end.inc
|
include/rpl_end.inc
|
||||||
|
@ -161,8 +161,8 @@ EOF
|
|||||||
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
wait
|
wait
|
||||||
EOF
|
EOF
|
||||||
SET GLOBAL debug_dbug="+d,crash_commit_before";
|
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
|
SET GLOBAL debug_dbug="+d,crash_commit_before";
|
||||||
|
|
||||||
--connection server_1
|
--connection server_1
|
||||||
INSERT INTO t1 VALUES (5);
|
INSERT INTO t1 VALUES (5);
|
||||||
@ -185,8 +185,8 @@ EOF
|
|||||||
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
wait
|
wait
|
||||||
EOF
|
EOF
|
||||||
SET GLOBAL debug_dbug="+d,crash_commit_after";
|
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
|
SET GLOBAL debug_dbug="+d,crash_commit_after";
|
||||||
|
|
||||||
--connection server_1
|
--connection server_1
|
||||||
INSERT INTO t1 VALUES (6);
|
INSERT INTO t1 VALUES (6);
|
||||||
|
@ -17,7 +17,7 @@ INSERT INTO t1 VALUES (1);
|
|||||||
|
|
||||||
--connection slave
|
--connection slave
|
||||||
CALL mtr.add_suppression("Slave: Failed to open mysql.gtid_slave_pos");
|
CALL mtr.add_suppression("Slave: Failed to open mysql.gtid_slave_pos");
|
||||||
--let $slave_sql_errno=1942
|
--let $slave_sql_errno=1944
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
--source include/stop_slave.inc
|
--source include/stop_slave.inc
|
||||||
@ -25,19 +25,19 @@ ALTER TABLE mysql.gtid_slave_pos CHANGE seq_no seq_no BIGINT UNSIGNED NOT NULL;
|
|||||||
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
||||||
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id, domain_id);
|
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id, domain_id);
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
--let $slave_sql_errno=1942
|
--let $slave_sql_errno=1944
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
--source include/stop_slave.inc
|
--source include/stop_slave.inc
|
||||||
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
--let $slave_sql_errno=1942
|
--let $slave_sql_errno=1944
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
--source include/stop_slave.inc
|
--source include/stop_slave.inc
|
||||||
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id);
|
ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id);
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
--let $slave_sql_errno=1942
|
--let $slave_sql_errno=1944
|
||||||
--source include/wait_for_slave_sql_error.inc
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
--source include/stop_slave.inc
|
--source include/stop_slave.inc
|
||||||
|
@ -129,6 +129,7 @@ SELECT * FROM t1 ORDER BY a;
|
|||||||
# Clean up.
|
# Clean up.
|
||||||
--connection server_1
|
--connection server_1
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
|
SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode;
|
||||||
SET debug_sync = "reset";
|
SET debug_sync = "reset";
|
||||||
|
|
||||||
|
@ -2,6 +2,18 @@
|
|||||||
--source include/have_innodb.inc
|
--source include/have_innodb.inc
|
||||||
--source include/have_debug.inc
|
--source include/have_debug.inc
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
# Since we inject an error updating mysql.gtid_slave_pos, we will get different
|
||||||
|
# output depending on whether it is InnoDB or MyISAM (roll back or no roll
|
||||||
|
# back). So fix it to make sure we are consistent, in case an earlier test case
|
||||||
|
# left it as InnoDB.
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
--connection master
|
||||||
CREATE TABLE t1 (i int) ENGINE=InnoDB;
|
CREATE TABLE t1 (i int) ENGINE=InnoDB;
|
||||||
|
|
||||||
--sync_slave_with_master
|
--sync_slave_with_master
|
||||||
@ -20,10 +32,6 @@ SET @old_dbug= @@GLOBAL.debug_dbug;
|
|||||||
SET GLOBAL debug_dbug="+d,gtid_slave_pos_simulate_failed_delete";
|
SET GLOBAL debug_dbug="+d,gtid_slave_pos_simulate_failed_delete";
|
||||||
SET sql_log_bin= 0;
|
SET sql_log_bin= 0;
|
||||||
CALL mtr.add_suppression("Can't find file");
|
CALL mtr.add_suppression("Can't find file");
|
||||||
# Since we inject an error updating mysql.gtid_slave_pos, we will get different
|
|
||||||
# output depending on whether it is InnoDB or MyISAM (roll back or no roll
|
|
||||||
# back). So fix it to make sure we are consistent.
|
|
||||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
|
||||||
SET sql_log_bin= 1;
|
SET sql_log_bin= 1;
|
||||||
--source include/start_slave.inc
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
@ -232,6 +232,20 @@ EOF
|
|||||||
SET sql_log_bin= 0;
|
SET sql_log_bin= 0;
|
||||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
SET sql_log_bin= 1;
|
SET sql_log_bin= 1;
|
||||||
|
# Do a second restart to get the mysql.gtid_slave_pos table loaded with
|
||||||
|
# the right engine.
|
||||||
|
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
wait
|
||||||
|
EOF
|
||||||
|
--shutdown_server 30
|
||||||
|
--source include/wait_until_disconnected.inc
|
||||||
|
|
||||||
|
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
restart:
|
||||||
|
EOF
|
||||||
|
--enable_reconnect
|
||||||
|
--source include/wait_until_connected_again.inc
|
||||||
|
|
||||||
--source include/start_slave.inc
|
--source include/start_slave.inc
|
||||||
|
|
||||||
--connection server_1
|
--connection server_1
|
||||||
@ -285,7 +299,7 @@ SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
|||||||
--connection server_2
|
--connection server_2
|
||||||
SET sql_log_bin=0;
|
SET sql_log_bin=0;
|
||||||
--let $old_pos= `SELECT @@GLOBAL.gtid_slave_pos`
|
--let $old_pos= `SELECT @@GLOBAL.gtid_slave_pos`
|
||||||
RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_old;
|
RENAME TABLE mysql.gtid_slave_pos TO mysql.old_gtid_slave_pos;
|
||||||
SET sql_log_bin=1;
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
@ -313,7 +327,7 @@ SHOW WARNINGS;
|
|||||||
# Restore things.
|
# Restore things.
|
||||||
|
|
||||||
SET sql_log_bin=0;
|
SET sql_log_bin=0;
|
||||||
RENAME TABLE mysql.gtid_slave_pos_old TO mysql.gtid_slave_pos;
|
RENAME TABLE mysql.old_gtid_slave_pos TO mysql.gtid_slave_pos;
|
||||||
CALL mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos");
|
CALL mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos");
|
||||||
SET sql_log_bin=1;
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@ delimiter ;|
|
|||||||
|
|
||||||
--connection server_2
|
--connection server_2
|
||||||
--sync_with_master
|
--sync_with_master
|
||||||
|
# Restart SQL thread to pick up ALTER TABLE of mysql.gtid_slave_pos.
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
# Both replication threads must be stopped for UNTIL master_gtid_pos.
|
# Both replication threads must be stopped for UNTIL master_gtid_pos.
|
||||||
--error ER_SLAVE_WAS_RUNNING
|
--error ER_SLAVE_WAS_RUNNING
|
||||||
|
@ -99,6 +99,7 @@ SET GLOBAL max_relay_log_size= @old_max_relay;
|
|||||||
--source include/start_slave.inc
|
--source include/start_slave.inc
|
||||||
|
|
||||||
--connection server_1
|
--connection server_1
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
--source include/rpl_end.inc
|
--source include/rpl_end.inc
|
||||||
|
280
mysql-test/suite/rpl/t/rpl_mdev12179.test
Normal file
280
mysql-test/suite/rpl/t/rpl_mdev12179.test
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
--source include/have_innodb.inc
|
||||||
|
--let $rpl_topology=1->2
|
||||||
|
--source include/rpl_init.inc
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--error ER_SLAVE_MUST_STOP
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb";
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
CHANGE MASTER TO master_use_gtid=slave_pos;
|
||||||
|
|
||||||
|
# Test the @@gtid_pos_auto_engines sysvar.
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||||
|
SELECT @@SESSION.gtid_pos_auto_engines;
|
||||||
|
--error ER_WRONG_VALUE_FOR_VAR
|
||||||
|
SET GLOBAL gtid_pos_auto_engines= NULL;
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="myisam,innodb";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb,myisam";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb,innodb,myisam,innodb,myisam,myisam,innodb";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
SET GLOBAL gtid_pos_auto_engines=DEFAULT;
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="";
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
--save_master_pos
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
# Reset storage engine for mysql.gtid_slave_pos in case an earlier test
|
||||||
|
# might have changed it to InnoDB.
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_innodb LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_innodb ENGINE=InnoDB;
|
||||||
|
INSERT INTO mysql.gtid_slave_pos_innodb SELECT * FROM mysql.gtid_slave_pos;
|
||||||
|
TRUNCATE mysql.gtid_slave_pos;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
|
# Restart the slave mysqld server, and verify that the GTID position is
|
||||||
|
# read correctly from the new mysql.gtid_slave_pos_innodb table.
|
||||||
|
|
||||||
|
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
wait
|
||||||
|
EOF
|
||||||
|
--shutdown_server 30
|
||||||
|
--source include/wait_until_disconnected.inc
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t1 VALUES (2);
|
||||||
|
INSERT INTO t1 VALUES (3);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
# Let the slave mysqld server start again.
|
||||||
|
# As we are restarting, also take the opportunity to test --gtid-pos-auto-engines
|
||||||
|
--echo *** Restart server with --gtid-pos-auto-engines=innodb,myisam ***
|
||||||
|
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
restart: --skip-slave-start=0 --gtid-pos-auto-engines=innodb,myisam
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--enable_reconnect
|
||||||
|
--source include/wait_until_connected_again.inc
|
||||||
|
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
|
||||||
|
--echo *** Verify no new gtid_slave_pos* tables are created ***
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
|
||||||
|
SELECT @@gtid_pos_auto_engines;
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
INSERT INTO mysql.gtid_slave_pos_innodb SELECT * FROM mysql.gtid_slave_pos;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos;
|
||||||
|
RENAME TABLE mysql.gtid_slave_pos_innodb TO mysql.gtid_slave_pos;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
|
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
wait
|
||||||
|
EOF
|
||||||
|
--shutdown_server 30
|
||||||
|
--source include/wait_until_disconnected.inc
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES (4);
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--echo *** Restart server with --gtid-pos-auto-engines=myisam,innodb ***
|
||||||
|
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
restart: --skip-slave-start=0 --gtid-pos-auto-engines=myisam,innodb
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--enable_reconnect
|
||||||
|
--source include/wait_until_connected_again.inc
|
||||||
|
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
|
||||||
|
--echo *** Verify that no new gtid_slave_pos* tables are auto-created ***
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
|
||||||
|
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=MyISAM;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
|
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
wait
|
||||||
|
EOF
|
||||||
|
--shutdown_server 30
|
||||||
|
--source include/wait_until_disconnected.inc
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t1 VALUES (5);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
--echo *** Restart server with --gtid-pos-auto-engines=innodb ***
|
||||||
|
restart: --skip-slave-start=0 --gtid-pos-auto-engines=innodb
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--enable_reconnect
|
||||||
|
--source include/wait_until_connected_again.inc
|
||||||
|
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
|
||||||
|
--echo *** Verify that mysql.gtid_slave_pos_InnoDB is auto-created ***
|
||||||
|
# Note, the create happens asynchronously, so wait for it.
|
||||||
|
let $wait_condition=
|
||||||
|
SELECT EXISTS (SELECT * FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name='gtid_slave_pos_InnoDB');
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
|
||||||
|
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
INSERT INTO mysql.gtid_slave_pos SELECT * FROM mysql.gtid_slave_pos_InnoDB;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_InnoDB;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
|
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
wait
|
||||||
|
EOF
|
||||||
|
--shutdown_server 30
|
||||||
|
--source include/wait_until_disconnected.inc
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t1 VALUES (6);
|
||||||
|
INSERT INTO t2 VALUES (3);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--echo *** Restart server without --gtid-pos-auto-engines ***
|
||||||
|
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
restart: --skip-slave-start=0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--enable_reconnect
|
||||||
|
--source include/wait_until_connected_again.inc
|
||||||
|
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
|
||||||
|
--echo *** Verify that no mysql.gtid_slave_pos* table is auto-created ***
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="innodb";
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t1 VALUES (7);
|
||||||
|
INSERT INTO t2 VALUES (4);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
|
||||||
|
--echo *** Verify that mysql.gtid_slave_pos_InnoDB is auto-created ***
|
||||||
|
let $wait_condition=
|
||||||
|
SELECT EXISTS (SELECT * FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name='gtid_slave_pos_InnoDB');
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
SELECT table_name, engine FROM information_schema.tables
|
||||||
|
WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%'
|
||||||
|
ORDER BY table_name;
|
||||||
|
SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id;
|
||||||
|
|
||||||
|
# Check that the auto-created InnoDB table starts being used without
|
||||||
|
# needing slave restart. The auto-create happens asynchronously, so it
|
||||||
|
# is non-deterministic when it will start being used. But we can wait
|
||||||
|
# for it to happen.
|
||||||
|
|
||||||
|
--let $count=300
|
||||||
|
--let $done=0
|
||||||
|
--let $old_silent= $keep_include_silent
|
||||||
|
--let $keep_include_silent= 1
|
||||||
|
--disable_query_log
|
||||||
|
while (!$done)
|
||||||
|
{
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t2(a) SELECT 1+MAX(a) FROM t2;
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
--let $done=`SELECT COUNT(*) > 0 FROM mysql.gtid_slave_pos_InnoDB`
|
||||||
|
if (!$done)
|
||||||
|
{
|
||||||
|
dec $count;
|
||||||
|
if (!$count)
|
||||||
|
{
|
||||||
|
SELECT * FROM mysql.gtid_slave_pos_InnoDB;
|
||||||
|
--die Timeout waiting for mysql.gtid_slave_pos_InnoDB to be used
|
||||||
|
}
|
||||||
|
real_sleep 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--enable_query_log
|
||||||
|
--let $keep_include_silent=$old_silent
|
||||||
|
# Note that at this point, the contents of table t2, as well as the GTID
|
||||||
|
# position, is non-deterministic.
|
||||||
|
|
||||||
|
|
||||||
|
#--connection server_2
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET GLOBAL gtid_pos_auto_engines="";
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_InnoDB;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
|
||||||
|
--source include/rpl_end.inc
|
@ -15,6 +15,7 @@ call mtr.add_suppression("Master is configured to log replication events");
|
|||||||
# All done.
|
# All done.
|
||||||
|
|
||||||
--connection slave
|
--connection slave
|
||||||
|
--source include/wait_for_slave_to_stop.inc
|
||||||
start slave;
|
start slave;
|
||||||
|
|
||||||
--connection master
|
--connection master
|
||||||
|
@ -1115,6 +1115,20 @@ NUMERIC_BLOCK_SIZE NULL
|
|||||||
ENUM_VALUE_LIST OFF,ON
|
ENUM_VALUE_LIST OFF,ON
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT OPTIONAL
|
COMMAND_LINE_ARGUMENT OPTIONAL
|
||||||
|
VARIABLE_NAME GTID_POS_AUTO_ENGINES
|
||||||
|
SESSION_VALUE NULL
|
||||||
|
GLOBAL_VALUE
|
||||||
|
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||||
|
DEFAULT_VALUE
|
||||||
|
VARIABLE_SCOPE GLOBAL
|
||||||
|
VARIABLE_TYPE VARCHAR
|
||||||
|
VARIABLE_COMMENT List of engines for which to automatically create a mysql.gtid_slave_pos_ENGINE table, if a transaction using that engine is replicated. This can be used to avoid introducing cross-engine transactions, if engines are used different from that used by table mysql.gtid_slave_pos
|
||||||
|
NUMERIC_MIN_VALUE NULL
|
||||||
|
NUMERIC_MAX_VALUE NULL
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT NULL
|
||||||
VARIABLE_NAME GTID_SEQ_NO
|
VARIABLE_NAME GTID_SEQ_NO
|
||||||
SESSION_VALUE 0
|
SESSION_VALUE 0
|
||||||
GLOBAL_VALUE NULL
|
GLOBAL_VALUE NULL
|
||||||
|
@ -224,6 +224,8 @@ CREATE TABLE IF NOT EXISTS column_stats (db_name varchar(64) NOT NULL, table_nam
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS index_stats (db_name varchar(64) NOT NULL, table_name varchar(64) NOT NULL, index_name varchar(64) NOT NULL, prefix_arity int(11) unsigned NOT NULL, avg_frequency decimal(12,4) DEFAULT NULL, PRIMARY KEY (db_name,table_name,index_name,prefix_arity) ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Statistics on Indexes';
|
CREATE TABLE IF NOT EXISTS index_stats (db_name varchar(64) NOT NULL, table_name varchar(64) NOT NULL, index_name varchar(64) NOT NULL, prefix_arity int(11) unsigned NOT NULL, avg_frequency decimal(12,4) DEFAULT NULL, PRIMARY KEY (db_name,table_name,index_name,prefix_arity) ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Statistics on Indexes';
|
||||||
|
|
||||||
|
-- Note: This definition must be kept in sync with the one used in
|
||||||
|
-- build_gtid_pos_create_query() in sql/slave.cc
|
||||||
SET @cmd= "CREATE TABLE IF NOT EXISTS gtid_slave_pos (
|
SET @cmd= "CREATE TABLE IF NOT EXISTS gtid_slave_pos (
|
||||||
domain_id INT UNSIGNED NOT NULL,
|
domain_id INT UNSIGNED NOT NULL,
|
||||||
sub_id BIGINT UNSIGNED NOT NULL,
|
sub_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
@ -1546,6 +1546,7 @@ static int
|
|||||||
commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
|
commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
|
||||||
{
|
{
|
||||||
int error= 0;
|
int error= 0;
|
||||||
|
uint count= 0;
|
||||||
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
|
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
|
||||||
DBUG_ENTER("commit_one_phase_2");
|
DBUG_ENTER("commit_one_phase_2");
|
||||||
if (is_real_trans)
|
if (is_real_trans)
|
||||||
@ -1563,6 +1564,8 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
|
|||||||
}
|
}
|
||||||
/* Should this be done only if is_real_trans is set ? */
|
/* Should this be done only if is_real_trans is set ? */
|
||||||
status_var_increment(thd->status_var.ha_commit_count);
|
status_var_increment(thd->status_var.ha_commit_count);
|
||||||
|
if (is_real_trans && ht != binlog_hton && ha_info->is_trx_read_write())
|
||||||
|
++count;
|
||||||
ha_info_next= ha_info->next();
|
ha_info_next= ha_info->next();
|
||||||
ha_info->reset(); /* keep it conveniently zero-filled */
|
ha_info->reset(); /* keep it conveniently zero-filled */
|
||||||
}
|
}
|
||||||
@ -1581,6 +1584,8 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
|
|||||||
{
|
{
|
||||||
thd->has_waiter= false;
|
thd->has_waiter= false;
|
||||||
thd->transaction.cleanup();
|
thd->transaction.cleanup();
|
||||||
|
if (count >= 2)
|
||||||
|
statistic_increment(transactions_multi_engine, LOCK_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
|
@ -1096,6 +1096,7 @@ void make_default_log_name(char **out, const char* log_ext, bool once);
|
|||||||
void binlog_reset_cache(THD *thd);
|
void binlog_reset_cache(THD *thd);
|
||||||
|
|
||||||
extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
|
extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
|
||||||
|
extern handlerton *binlog_hton;
|
||||||
extern LOGGER logger;
|
extern LOGGER logger;
|
||||||
|
|
||||||
extern const char *log_bin_index;
|
extern const char *log_bin_index;
|
||||||
|
@ -5027,6 +5027,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
|
|||||||
int expected_error,actual_error= 0;
|
int expected_error,actual_error= 0;
|
||||||
Schema_specification_st db_options;
|
Schema_specification_st db_options;
|
||||||
uint64 sub_id= 0;
|
uint64 sub_id= 0;
|
||||||
|
void *hton= NULL;
|
||||||
rpl_gtid gtid;
|
rpl_gtid gtid;
|
||||||
Relay_log_info const *rli= rgi->rli;
|
Relay_log_info const *rli= rgi->rli;
|
||||||
Rpl_filter *rpl_filter= rli->mi->rpl_filter;
|
Rpl_filter *rpl_filter= rli->mi->rpl_filter;
|
||||||
@ -5197,7 +5198,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
|
|||||||
|
|
||||||
gtid= rgi->current_gtid;
|
gtid= rgi->current_gtid;
|
||||||
if (rpl_global_gtid_slave_state->record_gtid(thd, >id, sub_id,
|
if (rpl_global_gtid_slave_state->record_gtid(thd, >id, sub_id,
|
||||||
true, false))
|
true, false, &hton))
|
||||||
{
|
{
|
||||||
int errcode= thd->get_stmt_da()->sql_errno();
|
int errcode= thd->get_stmt_da()->sql_errno();
|
||||||
if (!is_parallel_retry_error(rgi, errcode))
|
if (!is_parallel_retry_error(rgi, errcode))
|
||||||
@ -5418,7 +5419,7 @@ compare_errors:
|
|||||||
|
|
||||||
end:
|
end:
|
||||||
if (sub_id && !thd->is_slave_error)
|
if (sub_id && !thd->is_slave_error)
|
||||||
rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, rgi);
|
rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, hton, rgi);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Probably we have set thd->query, thd->db, thd->catalog to point to places
|
Probably we have set thd->query, thd->db, thd->catalog to point to places
|
||||||
@ -7901,15 +7902,17 @@ Gtid_list_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
int ret;
|
int ret;
|
||||||
if (gl_flags & FLAG_IGN_GTIDS)
|
if (gl_flags & FLAG_IGN_GTIDS)
|
||||||
{
|
{
|
||||||
|
void *hton= NULL;
|
||||||
uint32 i;
|
uint32 i;
|
||||||
|
|
||||||
for (i= 0; i < count; ++i)
|
for (i= 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
if ((ret= rpl_global_gtid_slave_state->record_gtid(thd, &list[i],
|
if ((ret= rpl_global_gtid_slave_state->record_gtid(thd, &list[i],
|
||||||
sub_id_list[i],
|
sub_id_list[i],
|
||||||
false, false)))
|
false, false, &hton)))
|
||||||
return ret;
|
return ret;
|
||||||
rpl_global_gtid_slave_state->update_state_hash(sub_id_list[i], &list[i],
|
rpl_global_gtid_slave_state->update_state_hash(sub_id_list[i], &list[i],
|
||||||
NULL);
|
hton, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret= Log_event::do_apply_event(rgi);
|
ret= Log_event::do_apply_event(rgi);
|
||||||
@ -8390,6 +8393,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
rpl_gtid gtid;
|
rpl_gtid gtid;
|
||||||
uint64 sub_id= 0;
|
uint64 sub_id= 0;
|
||||||
Relay_log_info const *rli= rgi->rli;
|
Relay_log_info const *rli= rgi->rli;
|
||||||
|
void *hton= NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
XID_EVENT works like a COMMIT statement. And it also updates the
|
XID_EVENT works like a COMMIT statement. And it also updates the
|
||||||
@ -8414,7 +8418,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
|
|
||||||
gtid= rgi->current_gtid;
|
gtid= rgi->current_gtid;
|
||||||
err= rpl_global_gtid_slave_state->record_gtid(thd, >id, sub_id, true,
|
err= rpl_global_gtid_slave_state->record_gtid(thd, >id, sub_id, true,
|
||||||
false);
|
false, &hton);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
int ec= thd->get_stmt_da()->sql_errno();
|
int ec= thd->get_stmt_da()->sql_errno();
|
||||||
@ -8447,7 +8451,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
thd->mdl_context.release_transactional_locks();
|
thd->mdl_context.release_transactional_locks();
|
||||||
|
|
||||||
if (!res && sub_id)
|
if (!res && sub_id)
|
||||||
rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, rgi);
|
rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, hton, rgi);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Increment the global status commit count variable
|
Increment the global status commit count variable
|
||||||
|
@ -372,6 +372,8 @@ char *my_bind_addr_str;
|
|||||||
static char *default_collation_name;
|
static char *default_collation_name;
|
||||||
char *default_storage_engine, *default_tmp_storage_engine;
|
char *default_storage_engine, *default_tmp_storage_engine;
|
||||||
char *enforced_storage_engine=NULL;
|
char *enforced_storage_engine=NULL;
|
||||||
|
char *gtid_pos_auto_engines;
|
||||||
|
plugin_ref *opt_gtid_pos_auto_plugins;
|
||||||
static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME;
|
static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME;
|
||||||
static I_List<CONNECT> thread_cache;
|
static I_List<CONNECT> thread_cache;
|
||||||
static bool binlog_format_used= false;
|
static bool binlog_format_used= false;
|
||||||
@ -523,6 +525,9 @@ ulong max_connections, max_connect_errors;
|
|||||||
ulong extra_max_connections;
|
ulong extra_max_connections;
|
||||||
uint max_digest_length= 0;
|
uint max_digest_length= 0;
|
||||||
ulong slave_retried_transactions;
|
ulong slave_retried_transactions;
|
||||||
|
ulong transactions_multi_engine;
|
||||||
|
ulong rpl_transactions_multi_engine;
|
||||||
|
ulong transactions_gtid_foreign_engine;
|
||||||
ulonglong slave_skipped_errors;
|
ulonglong slave_skipped_errors;
|
||||||
ulong feature_files_opened_with_delayed_keys= 0, feature_check_constraint= 0;
|
ulong feature_files_opened_with_delayed_keys= 0, feature_check_constraint= 0;
|
||||||
ulonglong denied_connections;
|
ulonglong denied_connections;
|
||||||
@ -4258,6 +4263,7 @@ static int init_common_variables()
|
|||||||
default_storage_engine= const_cast<char *>("MyISAM");
|
default_storage_engine= const_cast<char *>("MyISAM");
|
||||||
#endif
|
#endif
|
||||||
default_tmp_storage_engine= NULL;
|
default_tmp_storage_engine= NULL;
|
||||||
|
gtid_pos_auto_engines= const_cast<char *>("");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Add server status variables to the dynamic list of
|
Add server status variables to the dynamic list of
|
||||||
@ -4937,6 +4943,34 @@ static int init_default_storage_engine_impl(const char *opt_name,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
init_gtid_pos_auto_engines(void)
|
||||||
|
{
|
||||||
|
plugin_ref *plugins;
|
||||||
|
|
||||||
|
/*
|
||||||
|
For the command-line option --gtid_pos_auto_engines, we allow (and ignore)
|
||||||
|
engines that are unknown. This is convenient, since it allows to set
|
||||||
|
default auto-create engines that might not be used by particular users.
|
||||||
|
The option sets a list of storage engines that will have gtid position
|
||||||
|
table auto-created for them if needed. And if the engine is not available,
|
||||||
|
then it will certainly not be needed.
|
||||||
|
*/
|
||||||
|
if (gtid_pos_auto_engines)
|
||||||
|
plugins= resolve_engine_list(NULL, gtid_pos_auto_engines,
|
||||||
|
strlen(gtid_pos_auto_engines), false, false);
|
||||||
|
else
|
||||||
|
plugins= resolve_engine_list(NULL, "", 0, false, false);
|
||||||
|
if (!plugins)
|
||||||
|
return 1;
|
||||||
|
mysql_mutex_lock(&LOCK_global_system_variables);
|
||||||
|
opt_gtid_pos_auto_plugins= plugins;
|
||||||
|
mysql_mutex_unlock(&LOCK_global_system_variables);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int init_server_components()
|
static int init_server_components()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("init_server_components");
|
DBUG_ENTER("init_server_components");
|
||||||
@ -5374,6 +5408,9 @@ static int init_server_components()
|
|||||||
if (init_default_storage_engine(enforced_storage_engine, enforced_table_plugin))
|
if (init_default_storage_engine(enforced_storage_engine, enforced_table_plugin))
|
||||||
unireg_abort(1);
|
unireg_abort(1);
|
||||||
|
|
||||||
|
if (init_gtid_pos_auto_engines())
|
||||||
|
unireg_abort(1);
|
||||||
|
|
||||||
#ifdef USE_ARIA_FOR_TMP_TABLES
|
#ifdef USE_ARIA_FOR_TMP_TABLES
|
||||||
if (!ha_storage_engine_is_enabled(maria_hton) && !opt_bootstrap)
|
if (!ha_storage_engine_is_enabled(maria_hton) && !opt_bootstrap)
|
||||||
{
|
{
|
||||||
@ -7367,6 +7404,14 @@ struct my_option my_long_options[]=
|
|||||||
"Set up signals usable for debugging. Deprecated, use --debug-gdb instead.",
|
"Set up signals usable for debugging. Deprecated, use --debug-gdb instead.",
|
||||||
&opt_debugging, &opt_debugging,
|
&opt_debugging, &opt_debugging,
|
||||||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||||
|
{"gtid-pos-auto-engines", 0,
|
||||||
|
"List of engines for which to automatically create a "
|
||||||
|
"mysql.gtid_slave_pos_ENGINE table, if a transaction using that engine "
|
||||||
|
"is replicated. This can be used to avoid introducing cross-engine "
|
||||||
|
"transactions, if engines are used different from that used by table "
|
||||||
|
"mysql.gtid_slave_pos",
|
||||||
|
>id_pos_auto_engines, 0, 0, GET_STR, REQUIRED_ARG,
|
||||||
|
0, 0, 0, 0, 0, 0 },
|
||||||
#ifdef HAVE_LARGE_PAGE_OPTION
|
#ifdef HAVE_LARGE_PAGE_OPTION
|
||||||
{"super-large-pages", 0, "Enable support for super large pages.",
|
{"super-large-pages", 0, "Enable support for super large pages.",
|
||||||
&opt_super_large_pages, &opt_super_large_pages, 0,
|
&opt_super_large_pages, &opt_super_large_pages, 0,
|
||||||
@ -7764,7 +7809,7 @@ static int show_slaves_running(THD *thd, SHOW_VAR *var, char *buff)
|
|||||||
var->type= SHOW_LONGLONG;
|
var->type= SHOW_LONGLONG;
|
||||||
var->value= buff;
|
var->value= buff;
|
||||||
|
|
||||||
*((longlong *)buff)= any_slave_sql_running();
|
*((longlong *)buff)= any_slave_sql_running(false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -8539,6 +8584,9 @@ SHOW_VAR status_vars[]= {
|
|||||||
{"Threads_connected", (char*) &connection_count, SHOW_INT},
|
{"Threads_connected", (char*) &connection_count, SHOW_INT},
|
||||||
{"Threads_created", (char*) &thread_created, SHOW_LONG_NOFLUSH},
|
{"Threads_created", (char*) &thread_created, SHOW_LONG_NOFLUSH},
|
||||||
{"Threads_running", (char*) &thread_running, SHOW_INT},
|
{"Threads_running", (char*) &thread_running, SHOW_INT},
|
||||||
|
{"Transactions_multi_engine", (char*) &transactions_multi_engine, SHOW_LONG},
|
||||||
|
{"Rpl_transactions_multi_engine", (char*) &rpl_transactions_multi_engine, SHOW_LONG},
|
||||||
|
{"Transactions_gtid_foreign_engine", (char*) &transactions_gtid_foreign_engine, SHOW_LONG},
|
||||||
{"Update_scan", (char*) offsetof(STATUS_VAR, update_scan_count), SHOW_LONG_STATUS},
|
{"Update_scan", (char*) offsetof(STATUS_VAR, update_scan_count), SHOW_LONG_STATUS},
|
||||||
{"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC},
|
{"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC},
|
||||||
#ifdef ENABLED_PROFILING
|
#ifdef ENABLED_PROFILING
|
||||||
@ -8782,6 +8830,9 @@ static int mysql_init_variables(void)
|
|||||||
report_user= report_password = report_host= 0; /* TO BE DELETED */
|
report_user= report_password = report_host= 0; /* TO BE DELETED */
|
||||||
opt_relay_logname= opt_relaylog_index_name= 0;
|
opt_relay_logname= opt_relaylog_index_name= 0;
|
||||||
slave_retried_transactions= 0;
|
slave_retried_transactions= 0;
|
||||||
|
transactions_multi_engine= 0;
|
||||||
|
rpl_transactions_multi_engine= 0;
|
||||||
|
transactions_gtid_foreign_engine= 0;
|
||||||
log_bin_basename= NULL;
|
log_bin_basename= NULL;
|
||||||
log_bin_index= NULL;
|
log_bin_index= NULL;
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <my_global.h> /* MYSQL_PLUGIN_IMPORT, FN_REFLEN, FN_EXTLEN */
|
#include <my_global.h> /* MYSQL_PLUGIN_IMPORT, FN_REFLEN, FN_EXTLEN */
|
||||||
#include "sql_basic_types.h" /* query_id_t */
|
#include "sql_basic_types.h" /* query_id_t */
|
||||||
|
#include "sql_plugin.h"
|
||||||
#include "sql_bitmap.h" /* Bitmap */
|
#include "sql_bitmap.h" /* Bitmap */
|
||||||
#include "my_decimal.h" /* my_decimal */
|
#include "my_decimal.h" /* my_decimal */
|
||||||
#include "mysql_com.h" /* SERVER_VERSION_LENGTH */
|
#include "mysql_com.h" /* SERVER_VERSION_LENGTH */
|
||||||
@ -130,6 +131,9 @@ extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap;
|
|||||||
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
|
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
|
||||||
extern ulong slave_exec_mode_options, slave_ddl_exec_mode_options;
|
extern ulong slave_exec_mode_options, slave_ddl_exec_mode_options;
|
||||||
extern ulong slave_retried_transactions;
|
extern ulong slave_retried_transactions;
|
||||||
|
extern ulong transactions_multi_engine;
|
||||||
|
extern ulong rpl_transactions_multi_engine;
|
||||||
|
extern ulong transactions_gtid_foreign_engine;
|
||||||
extern ulong slave_run_triggers_for_rbr;
|
extern ulong slave_run_triggers_for_rbr;
|
||||||
extern ulonglong slave_type_conversions_options;
|
extern ulonglong slave_type_conversions_options;
|
||||||
extern my_bool read_only, opt_readonly;
|
extern my_bool read_only, opt_readonly;
|
||||||
@ -153,6 +157,8 @@ extern char *default_tz_name;
|
|||||||
extern Time_zone *default_tz;
|
extern Time_zone *default_tz;
|
||||||
extern char *default_storage_engine, *default_tmp_storage_engine;
|
extern char *default_storage_engine, *default_tmp_storage_engine;
|
||||||
extern char *enforced_storage_engine;
|
extern char *enforced_storage_engine;
|
||||||
|
extern char *gtid_pos_auto_engines;
|
||||||
|
extern plugin_ref *opt_gtid_pos_auto_plugins;
|
||||||
extern bool opt_endinfo, using_udf_functions;
|
extern bool opt_endinfo, using_udf_functions;
|
||||||
extern my_bool locked_in_memory;
|
extern my_bool locked_in_memory;
|
||||||
extern bool opt_using_transactions;
|
extern bool opt_using_transactions;
|
||||||
|
268
sql/rpl_gtid.cc
268
sql/rpl_gtid.cc
@ -26,6 +26,7 @@
|
|||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "rpl_gtid.h"
|
#include "rpl_gtid.h"
|
||||||
#include "rpl_rli.h"
|
#include "rpl_rli.h"
|
||||||
|
#include "slave.h"
|
||||||
|
|
||||||
|
|
||||||
const LEX_STRING rpl_gtid_slave_state_table_name=
|
const LEX_STRING rpl_gtid_slave_state_table_name=
|
||||||
@ -33,7 +34,7 @@ const LEX_STRING rpl_gtid_slave_state_table_name=
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
rpl_slave_state::update_state_hash(uint64 sub_id, rpl_gtid *gtid,
|
rpl_slave_state::update_state_hash(uint64 sub_id, rpl_gtid *gtid, void *hton,
|
||||||
rpl_group_info *rgi)
|
rpl_group_info *rgi)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@ -45,7 +46,7 @@ rpl_slave_state::update_state_hash(uint64 sub_id, rpl_gtid *gtid,
|
|||||||
it is even committed.
|
it is even committed.
|
||||||
*/
|
*/
|
||||||
mysql_mutex_lock(&LOCK_slave_state);
|
mysql_mutex_lock(&LOCK_slave_state);
|
||||||
err= update(gtid->domain_id, gtid->server_id, sub_id, gtid->seq_no, rgi);
|
err= update(gtid->domain_id, gtid->server_id, sub_id, gtid->seq_no, hton, rgi);
|
||||||
mysql_mutex_unlock(&LOCK_slave_state);
|
mysql_mutex_unlock(&LOCK_slave_state);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
@ -74,12 +75,14 @@ rpl_slave_state::record_and_update_gtid(THD *thd, rpl_group_info *rgi)
|
|||||||
if (rgi->gtid_pending)
|
if (rgi->gtid_pending)
|
||||||
{
|
{
|
||||||
uint64 sub_id= rgi->gtid_sub_id;
|
uint64 sub_id= rgi->gtid_sub_id;
|
||||||
|
void *hton= NULL;
|
||||||
|
|
||||||
rgi->gtid_pending= false;
|
rgi->gtid_pending= false;
|
||||||
if (rgi->gtid_ignore_duplicate_state!=rpl_group_info::GTID_DUPLICATE_IGNORE)
|
if (rgi->gtid_ignore_duplicate_state!=rpl_group_info::GTID_DUPLICATE_IGNORE)
|
||||||
{
|
{
|
||||||
if (record_gtid(thd, &rgi->current_gtid, sub_id, false, false))
|
if (record_gtid(thd, &rgi->current_gtid, sub_id, false, false, &hton))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
update_state_hash(sub_id, &rgi->current_gtid, rgi);
|
update_state_hash(sub_id, &rgi->current_gtid, hton, rgi);
|
||||||
}
|
}
|
||||||
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_NULL;
|
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_NULL;
|
||||||
}
|
}
|
||||||
@ -243,7 +246,7 @@ rpl_slave_state_free_element(void *arg)
|
|||||||
|
|
||||||
|
|
||||||
rpl_slave_state::rpl_slave_state()
|
rpl_slave_state::rpl_slave_state()
|
||||||
: last_sub_id(0), loaded(false)
|
: last_sub_id(0), gtid_pos_tables(0), loaded(false)
|
||||||
{
|
{
|
||||||
mysql_mutex_init(key_LOCK_slave_state, &LOCK_slave_state,
|
mysql_mutex_init(key_LOCK_slave_state, &LOCK_slave_state,
|
||||||
MY_MUTEX_INIT_SLOW);
|
MY_MUTEX_INIT_SLOW);
|
||||||
@ -255,6 +258,7 @@ rpl_slave_state::rpl_slave_state()
|
|||||||
|
|
||||||
rpl_slave_state::~rpl_slave_state()
|
rpl_slave_state::~rpl_slave_state()
|
||||||
{
|
{
|
||||||
|
free_gtid_pos_tables((struct gtid_pos_table *)gtid_pos_tables);
|
||||||
truncate_hash();
|
truncate_hash();
|
||||||
my_hash_free(&hash);
|
my_hash_free(&hash);
|
||||||
delete_dynamic(>id_sort_array);
|
delete_dynamic(>id_sort_array);
|
||||||
@ -286,11 +290,12 @@ rpl_slave_state::truncate_hash()
|
|||||||
|
|
||||||
int
|
int
|
||||||
rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id,
|
rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id,
|
||||||
uint64 seq_no, rpl_group_info *rgi)
|
uint64 seq_no, void *hton, rpl_group_info *rgi)
|
||||||
{
|
{
|
||||||
element *elem= NULL;
|
element *elem= NULL;
|
||||||
list_element *list_elem= NULL;
|
list_element *list_elem= NULL;
|
||||||
|
|
||||||
|
DBUG_ASSERT(hton || !loaded);
|
||||||
if (!(elem= get_element(domain_id)))
|
if (!(elem= get_element(domain_id)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@ -335,6 +340,7 @@ rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id,
|
|||||||
list_elem->server_id= server_id;
|
list_elem->server_id= server_id;
|
||||||
list_elem->sub_id= sub_id;
|
list_elem->sub_id= sub_id;
|
||||||
list_elem->seq_no= seq_no;
|
list_elem->seq_no= seq_no;
|
||||||
|
list_elem->hton= hton;
|
||||||
|
|
||||||
elem->add(list_elem);
|
elem->add(list_elem);
|
||||||
if (last_sub_id < sub_id)
|
if (last_sub_id < sub_id)
|
||||||
@ -465,6 +471,94 @@ gtid_check_rpl_slave_state_table(TABLE *table)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Attempt to find a mysql.gtid_slave_posXXX table that has a storage engine
|
||||||
|
that is already in use by the current transaction, if any.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
rpl_slave_state::select_gtid_pos_table(THD *thd, LEX_STRING *out_tablename)
|
||||||
|
{
|
||||||
|
struct gtid_pos_table *list, *table_entry, *default_entry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
See comments on rpl_slave_state::gtid_pos_tables for rules around proper
|
||||||
|
access to the list.
|
||||||
|
*/
|
||||||
|
list= (struct gtid_pos_table *)
|
||||||
|
my_atomic_loadptr_explicit(>id_pos_tables, MY_MEMORY_ORDER_ACQUIRE);
|
||||||
|
|
||||||
|
Ha_trx_info *ha_info;
|
||||||
|
uint count = 0;
|
||||||
|
for (ha_info= thd->transaction.all.ha_list; ha_info; ha_info= ha_info->next())
|
||||||
|
{
|
||||||
|
void *trx_hton= ha_info->ht();
|
||||||
|
table_entry= list;
|
||||||
|
|
||||||
|
if (!ha_info->is_trx_read_write() || trx_hton == binlog_hton)
|
||||||
|
continue;
|
||||||
|
while (table_entry)
|
||||||
|
{
|
||||||
|
if (table_entry->table_hton == trx_hton)
|
||||||
|
{
|
||||||
|
if (likely(table_entry->state == GTID_POS_AVAILABLE))
|
||||||
|
{
|
||||||
|
*out_tablename= table_entry->table_name;
|
||||||
|
/*
|
||||||
|
Check if this is a cross-engine transaction, so we can correctly
|
||||||
|
maintain the rpl_transactions_multi_engine status variable.
|
||||||
|
*/
|
||||||
|
if (count >= 1)
|
||||||
|
statistic_increment(rpl_transactions_multi_engine, LOCK_status);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ha_info= ha_info->next();
|
||||||
|
if (!ha_info)
|
||||||
|
break;
|
||||||
|
if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton)
|
||||||
|
{
|
||||||
|
statistic_increment(rpl_transactions_multi_engine, LOCK_status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
This engine is marked to automatically create the table.
|
||||||
|
We cannot easily do this here (possibly in the middle of a
|
||||||
|
transaction). But we can request the slave background thread
|
||||||
|
to create it, and in a short while it should become available
|
||||||
|
for following transactions.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_REPLICATION
|
||||||
|
slave_background_gtid_pos_create_request(table_entry);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
table_entry= table_entry->next;
|
||||||
|
}
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
If we cannot find any table whose engine matches an engine that is
|
||||||
|
already active in the transaction, or if there is no current transaction
|
||||||
|
engines available, we return the default gtid_slave_pos table.
|
||||||
|
*/
|
||||||
|
default_entry= (struct gtid_pos_table *)
|
||||||
|
my_atomic_loadptr_explicit(&default_gtid_pos_table, MY_MEMORY_ORDER_ACQUIRE);
|
||||||
|
*out_tablename= default_entry->table_name;
|
||||||
|
/* Record in status that we failed to find a suitable gtid_pos table. */
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
statistic_increment(transactions_gtid_foreign_engine, LOCK_status);
|
||||||
|
if (count > 1)
|
||||||
|
statistic_increment(rpl_transactions_multi_engine, LOCK_status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write a gtid to the replication slave state table.
|
Write a gtid to the replication slave state table.
|
||||||
|
|
||||||
@ -481,19 +575,24 @@ gtid_check_rpl_slave_state_table(TABLE *table)
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
||||||
bool in_transaction, bool in_statement)
|
bool in_transaction, bool in_statement,
|
||||||
|
void **out_hton)
|
||||||
{
|
{
|
||||||
TABLE_LIST tlist;
|
TABLE_LIST tlist;
|
||||||
int err= 0;
|
int err= 0;
|
||||||
bool table_opened= false;
|
bool table_opened= false;
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
list_element *elist= 0, *next;
|
list_element *delete_list= 0, *next, *cur, **next_ptr_ptr, **best_ptr_ptr;
|
||||||
|
uint64_t best_sub_id;
|
||||||
element *elem;
|
element *elem;
|
||||||
ulonglong thd_saved_option= thd->variables.option_bits;
|
ulonglong thd_saved_option= thd->variables.option_bits;
|
||||||
Query_tables_list lex_backup;
|
Query_tables_list lex_backup;
|
||||||
wait_for_commit* suspended_wfc;
|
wait_for_commit* suspended_wfc;
|
||||||
|
void *hton= NULL;
|
||||||
|
LEX_STRING gtid_pos_table_name;
|
||||||
DBUG_ENTER("record_gtid");
|
DBUG_ENTER("record_gtid");
|
||||||
|
|
||||||
|
*out_hton= NULL;
|
||||||
if (unlikely(!loaded))
|
if (unlikely(!loaded))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -508,6 +607,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
|||||||
|
|
||||||
if (!in_statement)
|
if (!in_statement)
|
||||||
thd->reset_for_next_command();
|
thd->reset_for_next_command();
|
||||||
|
select_gtid_pos_table(thd, >id_pos_table_name);
|
||||||
|
|
||||||
DBUG_EXECUTE_IF("gtid_inject_record_gtid",
|
DBUG_EXECUTE_IF("gtid_inject_record_gtid",
|
||||||
{
|
{
|
||||||
@ -538,14 +638,13 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
|||||||
*/
|
*/
|
||||||
suspended_wfc= thd->suspend_subsequent_commits();
|
suspended_wfc= thd->suspend_subsequent_commits();
|
||||||
thd->lex->reset_n_backup_query_tables_list(&lex_backup);
|
thd->lex->reset_n_backup_query_tables_list(&lex_backup);
|
||||||
tlist.init_one_table(STRING_WITH_LEN("mysql"),
|
tlist.init_one_table(STRING_WITH_LEN("mysql"), gtid_pos_table_name.str,
|
||||||
rpl_gtid_slave_state_table_name.str,
|
gtid_pos_table_name.length, NULL, TL_WRITE);
|
||||||
rpl_gtid_slave_state_table_name.length,
|
|
||||||
NULL, TL_WRITE);
|
|
||||||
if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0)))
|
if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0)))
|
||||||
goto end;
|
goto end;
|
||||||
table_opened= true;
|
table_opened= true;
|
||||||
table= tlist.table;
|
table= tlist.table;
|
||||||
|
hton= table->s->db_type();
|
||||||
|
|
||||||
if ((err= gtid_check_rpl_slave_state_table(table)))
|
if ((err= gtid_check_rpl_slave_state_table(table)))
|
||||||
goto end;
|
goto end;
|
||||||
@ -581,6 +680,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
|||||||
table->file->print_error(err, MYF(0));
|
table->file->print_error(err, MYF(0));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
*out_hton= hton;
|
||||||
|
|
||||||
if(opt_bin_log &&
|
if(opt_bin_log &&
|
||||||
(err= mysql_bin_log.bump_seq_no_counter_if_needed(gtid->domain_id,
|
(err= mysql_bin_log.bump_seq_no_counter_if_needed(gtid->domain_id,
|
||||||
@ -598,36 +698,62 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
|||||||
err= 1;
|
err= 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if ((elist= elem->grab_list()) != NULL)
|
|
||||||
|
/* Now pull out all GTIDs that were recorded in this engine. */
|
||||||
|
delete_list = NULL;
|
||||||
|
next_ptr_ptr= &elem->list;
|
||||||
|
cur= elem->list;
|
||||||
|
best_sub_id= 0;
|
||||||
|
best_ptr_ptr= NULL;
|
||||||
|
while (cur)
|
||||||
{
|
{
|
||||||
/* Delete any old stuff, but keep around the most recent one. */
|
list_element *next= cur->next;
|
||||||
list_element *cur= elist;
|
if (cur->hton == hton)
|
||||||
uint64 best_sub_id= cur->sub_id;
|
|
||||||
list_element **best_ptr_ptr= &elist;
|
|
||||||
while ((next= cur->next))
|
|
||||||
{
|
{
|
||||||
if (next->sub_id > best_sub_id)
|
/* Belongs to same engine, so move it to the delete list. */
|
||||||
|
cur->next= delete_list;
|
||||||
|
delete_list= cur;
|
||||||
|
if (cur->sub_id > best_sub_id)
|
||||||
{
|
{
|
||||||
best_sub_id= next->sub_id;
|
best_sub_id= cur->sub_id;
|
||||||
|
best_ptr_ptr= &delete_list;
|
||||||
|
}
|
||||||
|
else if (best_ptr_ptr == &delete_list)
|
||||||
best_ptr_ptr= &cur->next;
|
best_ptr_ptr= &cur->next;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Another engine, leave it in the list. */
|
||||||
|
if (cur->sub_id > best_sub_id)
|
||||||
|
{
|
||||||
|
best_sub_id= cur->sub_id;
|
||||||
|
/* Current best is not on the delete list. */
|
||||||
|
best_ptr_ptr= NULL;
|
||||||
|
}
|
||||||
|
*next_ptr_ptr= cur;
|
||||||
|
next_ptr_ptr= &cur->next;
|
||||||
|
}
|
||||||
cur= next;
|
cur= next;
|
||||||
}
|
}
|
||||||
|
*next_ptr_ptr= NULL;
|
||||||
/*
|
/*
|
||||||
Delete the highest sub_id element from the old list, and put it back as
|
If the highest sub_id element is on the delete list, put it back on the
|
||||||
the single-element new list.
|
original list, to preserve the highest sub_id element in the table for
|
||||||
|
GTID position recovery.
|
||||||
*/
|
*/
|
||||||
|
if (best_ptr_ptr)
|
||||||
|
{
|
||||||
cur= *best_ptr_ptr;
|
cur= *best_ptr_ptr;
|
||||||
*best_ptr_ptr= cur->next;
|
*best_ptr_ptr= cur->next;
|
||||||
cur->next= NULL;
|
cur->next= elem->list;
|
||||||
elem->list= cur;
|
elem->list= cur;
|
||||||
}
|
}
|
||||||
mysql_mutex_unlock(&LOCK_slave_state);
|
mysql_mutex_unlock(&LOCK_slave_state);
|
||||||
|
|
||||||
if (!elist)
|
if (!delete_list)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
/* Now delete any already committed rows. */
|
/* Now delete any already committed GTIDs. */
|
||||||
bitmap_set_bit(table->read_set, table->field[0]->field_index);
|
bitmap_set_bit(table->read_set, table->field[0]->field_index);
|
||||||
bitmap_set_bit(table->read_set, table->field[1]->field_index);
|
bitmap_set_bit(table->read_set, table->field[1]->field_index);
|
||||||
|
|
||||||
@ -636,7 +762,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
|||||||
table->file->print_error(err, MYF(0));
|
table->file->print_error(err, MYF(0));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
while (elist)
|
while (delete_list)
|
||||||
{
|
{
|
||||||
uchar key_buffer[4+8];
|
uchar key_buffer[4+8];
|
||||||
|
|
||||||
@ -646,9 +772,9 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
|||||||
/* `break' does not work inside DBUG_EXECUTE_IF */
|
/* `break' does not work inside DBUG_EXECUTE_IF */
|
||||||
goto dbug_break; });
|
goto dbug_break; });
|
||||||
|
|
||||||
next= elist->next;
|
next= delete_list->next;
|
||||||
|
|
||||||
table->field[1]->store(elist->sub_id, true);
|
table->field[1]->store(delete_list->sub_id, true);
|
||||||
/* domain_id is already set in table->record[0] from write_row() above. */
|
/* domain_id is already set in table->record[0] from write_row() above. */
|
||||||
key_copy(key_buffer, table->record[0], &table->key_info[0], 0, false);
|
key_copy(key_buffer, table->record[0], &table->key_info[0], 0, false);
|
||||||
if (table->file->ha_index_read_map(table->record[1], key_buffer,
|
if (table->file->ha_index_read_map(table->record[1], key_buffer,
|
||||||
@ -662,8 +788,8 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
|||||||
not want to endlessly error on the same element in case of table
|
not want to endlessly error on the same element in case of table
|
||||||
corruption or such.
|
corruption or such.
|
||||||
*/
|
*/
|
||||||
my_free(elist);
|
my_free(delete_list);
|
||||||
elist= next;
|
delete_list= next;
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -681,13 +807,13 @@ end:
|
|||||||
if (err || (err= ha_commit_trans(thd, FALSE)))
|
if (err || (err= ha_commit_trans(thd, FALSE)))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
If error, we need to put any remaining elist back into the HASH so we
|
If error, we need to put any remaining delete_list back into the HASH
|
||||||
can do another delete attempt later.
|
so we can do another delete attempt later.
|
||||||
*/
|
*/
|
||||||
if (elist)
|
if (delete_list)
|
||||||
{
|
{
|
||||||
mysql_mutex_lock(&LOCK_slave_state);
|
mysql_mutex_lock(&LOCK_slave_state);
|
||||||
put_back_list(gtid->domain_id, elist);
|
put_back_list(gtid->domain_id, delete_list);
|
||||||
mysql_mutex_unlock(&LOCK_slave_state);
|
mysql_mutex_unlock(&LOCK_slave_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1077,11 +1203,12 @@ rpl_slave_state::load(THD *thd, const char *state_from_master, size_t len,
|
|||||||
{
|
{
|
||||||
rpl_gtid gtid;
|
rpl_gtid gtid;
|
||||||
uint64 sub_id;
|
uint64 sub_id;
|
||||||
|
void *hton= NULL;
|
||||||
|
|
||||||
if (gtid_parser_helper(&state_from_master, end, >id) ||
|
if (gtid_parser_helper(&state_from_master, end, >id) ||
|
||||||
!(sub_id= next_sub_id(gtid.domain_id)) ||
|
!(sub_id= next_sub_id(gtid.domain_id)) ||
|
||||||
record_gtid(thd, >id, sub_id, false, in_statement) ||
|
record_gtid(thd, >id, sub_id, false, in_statement, &hton) ||
|
||||||
update(gtid.domain_id, gtid.server_id, sub_id, gtid.seq_no, NULL))
|
update(gtid.domain_id, gtid.server_id, sub_id, gtid.seq_no, hton, NULL))
|
||||||
return 1;
|
return 1;
|
||||||
if (state_from_master == end)
|
if (state_from_master == end)
|
||||||
break;
|
break;
|
||||||
@ -1115,6 +1242,75 @@ rpl_slave_state::is_empty()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
rpl_slave_state::free_gtid_pos_tables(struct rpl_slave_state::gtid_pos_table *list)
|
||||||
|
{
|
||||||
|
struct gtid_pos_table *cur, *next;
|
||||||
|
|
||||||
|
cur= list;
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
next= cur->next;
|
||||||
|
my_free(cur);
|
||||||
|
cur= next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Replace the list of available mysql.gtid_slave_posXXX tables with a new list.
|
||||||
|
The caller must be holding LOCK_slave_state. Additionally, this function
|
||||||
|
must only be called while all SQL threads are stopped.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
rpl_slave_state::set_gtid_pos_tables_list(rpl_slave_state::gtid_pos_table *new_list,
|
||||||
|
rpl_slave_state::gtid_pos_table *default_entry)
|
||||||
|
{
|
||||||
|
gtid_pos_table *old_list;
|
||||||
|
|
||||||
|
mysql_mutex_assert_owner(&LOCK_slave_state);
|
||||||
|
old_list= (struct gtid_pos_table *)gtid_pos_tables;
|
||||||
|
my_atomic_storeptr_explicit(>id_pos_tables, new_list, MY_MEMORY_ORDER_RELEASE);
|
||||||
|
my_atomic_storeptr_explicit(&default_gtid_pos_table, default_entry,
|
||||||
|
MY_MEMORY_ORDER_RELEASE);
|
||||||
|
free_gtid_pos_tables(old_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
rpl_slave_state::add_gtid_pos_table(rpl_slave_state::gtid_pos_table *entry)
|
||||||
|
{
|
||||||
|
mysql_mutex_assert_owner(&LOCK_slave_state);
|
||||||
|
entry->next= (struct gtid_pos_table *)gtid_pos_tables;
|
||||||
|
my_atomic_storeptr_explicit(>id_pos_tables, entry, MY_MEMORY_ORDER_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct rpl_slave_state::gtid_pos_table *
|
||||||
|
rpl_slave_state::alloc_gtid_pos_table(LEX_STRING *table_name, void *hton,
|
||||||
|
rpl_slave_state::gtid_pos_table_state state)
|
||||||
|
{
|
||||||
|
struct gtid_pos_table *p;
|
||||||
|
char *allocated_str;
|
||||||
|
|
||||||
|
if (!my_multi_malloc(MYF(MY_WME),
|
||||||
|
&p, sizeof(*p),
|
||||||
|
&allocated_str, table_name->length+1,
|
||||||
|
NULL))
|
||||||
|
{
|
||||||
|
my_error(ER_OUTOFMEMORY, MYF(0), (int)(sizeof(*p) + table_name->length+1));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(allocated_str, table_name->str, table_name->length+1); // Also copy '\0'
|
||||||
|
p->next = NULL;
|
||||||
|
p->table_hton= hton;
|
||||||
|
p->table_name.str= allocated_str;
|
||||||
|
p->table_name.length= table_name->length;
|
||||||
|
p->state= state;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void rpl_binlog_state::init()
|
void rpl_binlog_state::init()
|
||||||
{
|
{
|
||||||
my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id),
|
my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id),
|
||||||
|
@ -112,6 +112,12 @@ struct rpl_slave_state
|
|||||||
uint64 sub_id;
|
uint64 sub_id;
|
||||||
uint64 seq_no;
|
uint64 seq_no;
|
||||||
uint32 server_id;
|
uint32 server_id;
|
||||||
|
/*
|
||||||
|
hton of mysql.gtid_slave_pos* table used to record this GTID.
|
||||||
|
Can be NULL if the gtid table failed to load (eg. missing
|
||||||
|
mysql.gtid_slave_pos table following an upgrade).
|
||||||
|
*/
|
||||||
|
void *hton;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Elements in the HASH that hold the state for one domain_id. */
|
/* Elements in the HASH that hold the state for one domain_id. */
|
||||||
@ -155,6 +161,26 @@ struct rpl_slave_state
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Descriptor for mysql.gtid_slave_posXXX table in specific engine. */
|
||||||
|
enum gtid_pos_table_state {
|
||||||
|
GTID_POS_AUTO_CREATE,
|
||||||
|
GTID_POS_CREATE_REQUESTED,
|
||||||
|
GTID_POS_CREATE_IN_PROGRESS,
|
||||||
|
GTID_POS_AVAILABLE
|
||||||
|
};
|
||||||
|
struct gtid_pos_table {
|
||||||
|
struct gtid_pos_table *next;
|
||||||
|
/*
|
||||||
|
Use a void * here, rather than handlerton *, to make explicit that we
|
||||||
|
are not using the value to access any functionality in the engine. It
|
||||||
|
is just used as an opaque value to identify which engine we are using
|
||||||
|
for each GTID row.
|
||||||
|
*/
|
||||||
|
void *table_hton;
|
||||||
|
LEX_STRING table_name;
|
||||||
|
uint8 state;
|
||||||
|
};
|
||||||
|
|
||||||
/* Mapping from domain_id to its element. */
|
/* Mapping from domain_id to its element. */
|
||||||
HASH hash;
|
HASH hash;
|
||||||
/* Mutex protecting access to the state. */
|
/* Mutex protecting access to the state. */
|
||||||
@ -163,6 +189,30 @@ struct rpl_slave_state
|
|||||||
DYNAMIC_ARRAY gtid_sort_array;
|
DYNAMIC_ARRAY gtid_sort_array;
|
||||||
|
|
||||||
uint64 last_sub_id;
|
uint64 last_sub_id;
|
||||||
|
/*
|
||||||
|
List of tables available for durably storing the slave GTID position.
|
||||||
|
|
||||||
|
Accesses to this table is protected by LOCK_slave_state. However for
|
||||||
|
efficiency, there is also a provision for read access to it from a running
|
||||||
|
slave without lock.
|
||||||
|
|
||||||
|
An element can be added at the head of a list by storing the new
|
||||||
|
gtid_pos_tables pointer atomically with release semantics, to ensure that
|
||||||
|
the next pointer of the new element is visible to readers of the new list.
|
||||||
|
Other changes (like deleting or replacing elements) must happen only while
|
||||||
|
all SQL driver threads are stopped. LOCK_slave_state must be held in any
|
||||||
|
case.
|
||||||
|
|
||||||
|
The list can be read without lock by an SQL driver thread or worker thread
|
||||||
|
by reading the gtid_pos_tables pointer atomically with acquire semantics,
|
||||||
|
to ensure that it will see the correct next pointer of a new head element.
|
||||||
|
|
||||||
|
The type is struct gtid_pos_table *, but needs to be void * to allow using
|
||||||
|
my_atomic operations without violating C strict aliasing semantics.
|
||||||
|
*/
|
||||||
|
void * volatile gtid_pos_tables;
|
||||||
|
/* The default entry in gtid_pos_tables, mysql.gtid_slave_pos. */
|
||||||
|
void * volatile default_gtid_pos_table;
|
||||||
bool loaded;
|
bool loaded;
|
||||||
|
|
||||||
rpl_slave_state();
|
rpl_slave_state();
|
||||||
@ -171,10 +221,11 @@ struct rpl_slave_state
|
|||||||
void truncate_hash();
|
void truncate_hash();
|
||||||
ulong count() const { return hash.records; }
|
ulong count() const { return hash.records; }
|
||||||
int update(uint32 domain_id, uint32 server_id, uint64 sub_id,
|
int update(uint32 domain_id, uint32 server_id, uint64 sub_id,
|
||||||
uint64 seq_no, rpl_group_info *rgi);
|
uint64 seq_no, void *hton, rpl_group_info *rgi);
|
||||||
int truncate_state_table(THD *thd);
|
int truncate_state_table(THD *thd);
|
||||||
|
void select_gtid_pos_table(THD *thd, LEX_STRING *out_tablename);
|
||||||
int record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
int record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
||||||
bool in_transaction, bool in_statement);
|
bool in_transaction, bool in_statement, void **out_hton);
|
||||||
uint64 next_sub_id(uint32 domain_id);
|
uint64 next_sub_id(uint32 domain_id);
|
||||||
int iterate(int (*cb)(rpl_gtid *, void *), void *data,
|
int iterate(int (*cb)(rpl_gtid *, void *), void *data,
|
||||||
rpl_gtid *extra_gtids, uint32 num_extra,
|
rpl_gtid *extra_gtids, uint32 num_extra,
|
||||||
@ -188,10 +239,17 @@ struct rpl_slave_state
|
|||||||
element *get_element(uint32 domain_id);
|
element *get_element(uint32 domain_id);
|
||||||
int put_back_list(uint32 domain_id, list_element *list);
|
int put_back_list(uint32 domain_id, list_element *list);
|
||||||
|
|
||||||
void update_state_hash(uint64 sub_id, rpl_gtid *gtid, rpl_group_info *rgi);
|
void update_state_hash(uint64 sub_id, rpl_gtid *gtid, void *hton,
|
||||||
|
rpl_group_info *rgi);
|
||||||
int record_and_update_gtid(THD *thd, struct rpl_group_info *rgi);
|
int record_and_update_gtid(THD *thd, struct rpl_group_info *rgi);
|
||||||
int check_duplicate_gtid(rpl_gtid *gtid, rpl_group_info *rgi);
|
int check_duplicate_gtid(rpl_gtid *gtid, rpl_group_info *rgi);
|
||||||
void release_domain_owner(rpl_group_info *rgi);
|
void release_domain_owner(rpl_group_info *rgi);
|
||||||
|
void set_gtid_pos_tables_list(gtid_pos_table *new_list,
|
||||||
|
gtid_pos_table *default_entry);
|
||||||
|
void add_gtid_pos_table(gtid_pos_table *entry);
|
||||||
|
struct gtid_pos_table *alloc_gtid_pos_table(LEX_STRING *table_name,
|
||||||
|
void *hton, rpl_slave_state::gtid_pos_table_state state);
|
||||||
|
void free_gtid_pos_tables(struct gtid_pos_table *list);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1557,6 +1557,9 @@ bool give_error_if_slave_running(bool already_locked)
|
|||||||
/**
|
/**
|
||||||
any_slave_sql_running()
|
any_slave_sql_running()
|
||||||
|
|
||||||
|
@param
|
||||||
|
already_locked 0 if we need to lock, 1 if we have LOCK_active_mi_locked
|
||||||
|
|
||||||
@return
|
@return
|
||||||
0 No Slave SQL thread is running
|
0 No Slave SQL thread is running
|
||||||
# Number of slave SQL thread running
|
# Number of slave SQL thread running
|
||||||
@ -1567,18 +1570,18 @@ bool give_error_if_slave_running(bool already_locked)
|
|||||||
hash entries can't be accessed.
|
hash entries can't be accessed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint any_slave_sql_running()
|
uint any_slave_sql_running(bool already_locked)
|
||||||
{
|
{
|
||||||
uint count= 0;
|
uint count= 0;
|
||||||
HASH *hash;
|
HASH *hash;
|
||||||
DBUG_ENTER("any_slave_sql_running");
|
DBUG_ENTER("any_slave_sql_running");
|
||||||
|
|
||||||
|
if (!already_locked)
|
||||||
mysql_mutex_lock(&LOCK_active_mi);
|
mysql_mutex_lock(&LOCK_active_mi);
|
||||||
if (unlikely(shutdown_in_progress || !master_info_index))
|
if (unlikely(shutdown_in_progress || !master_info_index))
|
||||||
|
count= 1;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
mysql_mutex_unlock(&LOCK_active_mi);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
hash= &master_info_index->master_info_hash;
|
hash= &master_info_index->master_info_hash;
|
||||||
for (uint i= 0; i< hash->records; ++i)
|
for (uint i= 0; i< hash->records; ++i)
|
||||||
{
|
{
|
||||||
@ -1586,6 +1589,8 @@ uint any_slave_sql_running()
|
|||||||
if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN)
|
if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!already_locked)
|
||||||
mysql_mutex_unlock(&LOCK_active_mi);
|
mysql_mutex_unlock(&LOCK_active_mi);
|
||||||
DBUG_RETURN(count);
|
DBUG_RETURN(count);
|
||||||
}
|
}
|
||||||
|
@ -379,7 +379,7 @@ void create_logfile_name_with_suffix(char *res_file_name, size_t length,
|
|||||||
uchar *get_key_master_info(Master_info *mi, size_t *length,
|
uchar *get_key_master_info(Master_info *mi, size_t *length,
|
||||||
my_bool not_used __attribute__((unused)));
|
my_bool not_used __attribute__((unused)));
|
||||||
void free_key_master_info(Master_info *mi);
|
void free_key_master_info(Master_info *mi);
|
||||||
uint any_slave_sql_running();
|
uint any_slave_sql_running(bool already_locked);
|
||||||
bool give_error_if_slave_running(bool already_lock);
|
bool give_error_if_slave_running(bool already_lock);
|
||||||
|
|
||||||
#endif /* HAVE_REPLICATION */
|
#endif /* HAVE_REPLICATION */
|
||||||
|
@ -1466,7 +1466,7 @@ rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool,
|
|||||||
*/
|
*/
|
||||||
if (!new_count && !force)
|
if (!new_count && !force)
|
||||||
{
|
{
|
||||||
if (any_slave_sql_running())
|
if (any_slave_sql_running(false))
|
||||||
{
|
{
|
||||||
DBUG_PRINT("warning",
|
DBUG_PRINT("warning",
|
||||||
("SQL threads running while trying to reset parallel pool"));
|
("SQL threads running while trying to reset parallel pool"));
|
||||||
@ -1621,7 +1621,7 @@ err:
|
|||||||
int rpl_parallel_resize_pool_if_no_slaves(void)
|
int rpl_parallel_resize_pool_if_no_slaves(void)
|
||||||
{
|
{
|
||||||
/* master_info_index is set to NULL on shutdown */
|
/* master_info_index is set to NULL on shutdown */
|
||||||
if (opt_slave_parallel_threads > 0 && !any_slave_sql_running())
|
if (opt_slave_parallel_threads > 0 && !any_slave_sql_running(false))
|
||||||
return rpl_parallel_inactivate_pool(&global_rpl_thread_pool);
|
return rpl_parallel_inactivate_pool(&global_rpl_thread_pool);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
529
sql/rpl_rli.cc
529
sql/rpl_rli.cc
@ -32,6 +32,8 @@
|
|||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
#include <mysql/plugin.h>
|
#include <mysql/plugin.h>
|
||||||
#include <mysql/service_thd_wait.h>
|
#include <mysql/service_thd_wait.h>
|
||||||
|
#include "lock.h"
|
||||||
|
#include "sql_table.h"
|
||||||
|
|
||||||
static int count_relay_log_space(Relay_log_info* rli);
|
static int count_relay_log_space(Relay_log_info* rli);
|
||||||
|
|
||||||
@ -1466,41 +1468,22 @@ Relay_log_info::update_relay_log_state(rpl_gtid *gtid_list, uint32 count)
|
|||||||
|
|
||||||
|
|
||||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||||
int
|
struct gtid_pos_element { uint64 sub_id; rpl_gtid gtid; void *hton; };
|
||||||
rpl_load_gtid_slave_state(THD *thd)
|
|
||||||
|
static int
|
||||||
|
scan_one_gtid_slave_pos_table(THD *thd, HASH *hash, DYNAMIC_ARRAY *array,
|
||||||
|
LEX_STRING *tablename, void **out_hton)
|
||||||
{
|
{
|
||||||
TABLE_LIST tlist;
|
TABLE_LIST tlist;
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
bool table_opened= false;
|
bool table_opened= false;
|
||||||
bool table_scanned= false;
|
bool table_scanned= false;
|
||||||
bool array_inited= false;
|
struct gtid_pos_element tmp_entry, *entry;
|
||||||
struct local_element { uint64 sub_id; rpl_gtid gtid; };
|
|
||||||
struct local_element tmp_entry, *entry;
|
|
||||||
HASH hash;
|
|
||||||
DYNAMIC_ARRAY array;
|
|
||||||
int err= 0;
|
int err= 0;
|
||||||
uint32 i;
|
|
||||||
DBUG_ENTER("rpl_load_gtid_slave_state");
|
|
||||||
|
|
||||||
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
|
||||||
bool loaded= rpl_global_gtid_slave_state->loaded;
|
|
||||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
|
||||||
if (loaded)
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
|
|
||||||
my_hash_init(&hash, &my_charset_bin, 32,
|
|
||||||
offsetof(local_element, gtid) + offsetof(rpl_gtid, domain_id),
|
|
||||||
sizeof(uint32), NULL, my_free, HASH_UNIQUE);
|
|
||||||
if ((err= my_init_dynamic_array(&array, sizeof(local_element), 0, 0, MYF(0))))
|
|
||||||
goto end;
|
|
||||||
array_inited= true;
|
|
||||||
|
|
||||||
thd->reset_for_next_command();
|
thd->reset_for_next_command();
|
||||||
|
tlist.init_one_table(STRING_WITH_LEN("mysql"), tablename->str,
|
||||||
tlist.init_one_table(STRING_WITH_LEN("mysql"),
|
tablename->length, NULL, TL_READ);
|
||||||
rpl_gtid_slave_state_table_name.str,
|
|
||||||
rpl_gtid_slave_state_table_name.length,
|
|
||||||
NULL, TL_READ);
|
|
||||||
if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0)))
|
if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0)))
|
||||||
goto end;
|
goto end;
|
||||||
table_opened= true;
|
table_opened= true;
|
||||||
@ -1546,25 +1529,27 @@ rpl_load_gtid_slave_state(THD *thd)
|
|||||||
tmp_entry.gtid.domain_id= domain_id;
|
tmp_entry.gtid.domain_id= domain_id;
|
||||||
tmp_entry.gtid.server_id= server_id;
|
tmp_entry.gtid.server_id= server_id;
|
||||||
tmp_entry.gtid.seq_no= seq_no;
|
tmp_entry.gtid.seq_no= seq_no;
|
||||||
if ((err= insert_dynamic(&array, (uchar *)&tmp_entry)))
|
tmp_entry.hton= table->s->db_type();
|
||||||
|
if ((err= insert_dynamic(array, (uchar *)&tmp_entry)))
|
||||||
{
|
{
|
||||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rec= my_hash_search(&hash, (const uchar *)&domain_id, 0)))
|
if ((rec= my_hash_search(hash, (const uchar *)&domain_id, 0)))
|
||||||
{
|
{
|
||||||
entry= (struct local_element *)rec;
|
entry= (struct gtid_pos_element *)rec;
|
||||||
if (entry->sub_id >= sub_id)
|
if (entry->sub_id >= sub_id)
|
||||||
continue;
|
continue;
|
||||||
entry->sub_id= sub_id;
|
entry->sub_id= sub_id;
|
||||||
DBUG_ASSERT(entry->gtid.domain_id == domain_id);
|
DBUG_ASSERT(entry->gtid.domain_id == domain_id);
|
||||||
entry->gtid.server_id= server_id;
|
entry->gtid.server_id= server_id;
|
||||||
entry->gtid.seq_no= seq_no;
|
entry->gtid.seq_no= seq_no;
|
||||||
|
entry->hton= table->s->db_type();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(entry= (struct local_element *)my_malloc(sizeof(*entry),
|
if (!(entry= (struct gtid_pos_element *)my_malloc(sizeof(*entry),
|
||||||
MYF(MY_WME))))
|
MYF(MY_WME))))
|
||||||
{
|
{
|
||||||
my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*entry));
|
my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*entry));
|
||||||
@ -1575,7 +1560,8 @@ rpl_load_gtid_slave_state(THD *thd)
|
|||||||
entry->gtid.domain_id= domain_id;
|
entry->gtid.domain_id= domain_id;
|
||||||
entry->gtid.server_id= server_id;
|
entry->gtid.server_id= server_id;
|
||||||
entry->gtid.seq_no= seq_no;
|
entry->gtid.seq_no= seq_no;
|
||||||
if ((err= my_hash_insert(&hash, (uchar *)entry)))
|
entry->hton= table->s->db_type();
|
||||||
|
if ((err= my_hash_insert(hash, (uchar *)entry)))
|
||||||
{
|
{
|
||||||
my_free(entry);
|
my_free(entry);
|
||||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||||
@ -1583,45 +1569,6 @@ rpl_load_gtid_slave_state(THD *thd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
|
||||||
if (rpl_global_gtid_slave_state->loaded)
|
|
||||||
{
|
|
||||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i= 0; i < array.elements; ++i)
|
|
||||||
{
|
|
||||||
get_dynamic(&array, (uchar *)&tmp_entry, i);
|
|
||||||
if ((err= rpl_global_gtid_slave_state->update(tmp_entry.gtid.domain_id,
|
|
||||||
tmp_entry.gtid.server_id,
|
|
||||||
tmp_entry.sub_id,
|
|
||||||
tmp_entry.gtid.seq_no,
|
|
||||||
NULL)))
|
|
||||||
{
|
|
||||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
|
||||||
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i= 0; i < hash.records; ++i)
|
|
||||||
{
|
|
||||||
entry= (struct local_element *)my_hash_element(&hash, i);
|
|
||||||
if (opt_bin_log &&
|
|
||||||
mysql_bin_log.bump_seq_no_counter_if_needed(entry->gtid.domain_id,
|
|
||||||
entry->gtid.seq_no))
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
|
||||||
|
|
||||||
err= 0; /* Clear HA_ERR_END_OF_FILE */
|
err= 0; /* Clear HA_ERR_END_OF_FILE */
|
||||||
|
|
||||||
end:
|
end:
|
||||||
@ -1633,16 +1580,456 @@ end:
|
|||||||
}
|
}
|
||||||
if (table_opened)
|
if (table_opened)
|
||||||
{
|
{
|
||||||
|
*out_hton= table->s->db_type();
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->mdl_context.release_transactional_locks();
|
||||||
}
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Look for all tables mysql.gtid_slave_pos*. Read all rows from each such
|
||||||
|
table found into ARRAY. For each domain id, put the row with highest sub_id
|
||||||
|
into HASH.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
scan_all_gtid_slave_pos_table(THD *thd, int (*cb)(THD *, LEX_STRING *, void *),
|
||||||
|
void *cb_data)
|
||||||
|
{
|
||||||
|
static LEX_STRING mysql_db_name= {C_STRING_WITH_LEN("mysql")};
|
||||||
|
char path[FN_REFLEN];
|
||||||
|
MY_DIR *dirp;
|
||||||
|
|
||||||
|
thd->reset_for_next_command();
|
||||||
|
if (lock_schema_name(thd, mysql_db_name.str))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
build_table_filename(path, sizeof(path) - 1, mysql_db_name.str, "", "", 0);
|
||||||
|
if (!(dirp= my_dir(path, MYF(MY_DONT_SORT))))
|
||||||
|
{
|
||||||
|
my_error(ER_FILE_NOT_FOUND, MYF(0), path, my_errno);
|
||||||
|
close_thread_tables(thd);
|
||||||
|
thd->mdl_context.release_transactional_locks();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Dynamic_array<LEX_STRING*> files(dirp->number_of_files);
|
||||||
|
Discovered_table_list tl(thd, &files);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err= ha_discover_table_names(thd, &mysql_db_name, dirp, &tl, false);
|
||||||
|
my_dirend(dirp);
|
||||||
|
close_thread_tables(thd);
|
||||||
|
thd->mdl_context.release_transactional_locks();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
for (i = 0; i < files.elements(); ++i)
|
||||||
|
{
|
||||||
|
if (strncmp(files.at(i)->str,
|
||||||
|
rpl_gtid_slave_state_table_name.str,
|
||||||
|
rpl_gtid_slave_state_table_name.length) == 0)
|
||||||
|
{
|
||||||
|
if ((err= (*cb)(thd, files.at(i), cb_data)))
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct load_gtid_state_cb_data {
|
||||||
|
HASH *hash;
|
||||||
|
DYNAMIC_ARRAY *array;
|
||||||
|
struct rpl_slave_state::gtid_pos_table *table_list;
|
||||||
|
struct rpl_slave_state::gtid_pos_table *default_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_gtid_pos_table(THD *thd, LEX_STRING *table_name, void *hton,
|
||||||
|
struct load_gtid_state_cb_data *data)
|
||||||
|
{
|
||||||
|
struct rpl_slave_state::gtid_pos_table *p, *entry, **next_ptr;
|
||||||
|
bool is_default=
|
||||||
|
(strcmp(table_name->str, rpl_gtid_slave_state_table_name.str) == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ignore tables with duplicate storage engine, with a warning.
|
||||||
|
Prefer the default mysql.gtid_slave_pos over another table
|
||||||
|
mysql.gtid_slave_posXXX with the same storage engine.
|
||||||
|
*/
|
||||||
|
next_ptr= &data->table_list;
|
||||||
|
entry= data->table_list;
|
||||||
|
while (entry)
|
||||||
|
{
|
||||||
|
if (entry->table_hton == hton)
|
||||||
|
{
|
||||||
|
static const char *warning_msg= "Ignoring redundant table mysql.%s "
|
||||||
|
"since mysql.%s has the same storage engine";
|
||||||
|
if (!is_default)
|
||||||
|
{
|
||||||
|
/* Ignore the redundant table. */
|
||||||
|
sql_print_warning(warning_msg, table_name->str, entry->table_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sql_print_warning(warning_msg, entry->table_name, table_name->str);
|
||||||
|
/* Delete the redundant table, and proceed to add this one instead. */
|
||||||
|
*next_ptr= entry->next;
|
||||||
|
my_free(entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next_ptr= &entry->next;
|
||||||
|
entry= entry->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
p= rpl_global_gtid_slave_state->alloc_gtid_pos_table(table_name,
|
||||||
|
hton, rpl_slave_state::GTID_POS_AVAILABLE);
|
||||||
|
if (!p)
|
||||||
|
return 1;
|
||||||
|
p->next= data->table_list;
|
||||||
|
data->table_list= p;
|
||||||
|
if (is_default)
|
||||||
|
data->default_entry= p;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Put tables corresponding to @@gtid_pos_auto_engines at the end of the list,
|
||||||
|
marked to be auto-created if needed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
gtid_pos_auto_create_tables(rpl_slave_state::gtid_pos_table **list_ptr)
|
||||||
|
{
|
||||||
|
plugin_ref *auto_engines;
|
||||||
|
int err= 0;
|
||||||
|
mysql_mutex_lock(&LOCK_global_system_variables);
|
||||||
|
for (auto_engines= opt_gtid_pos_auto_plugins;
|
||||||
|
!err && auto_engines && *auto_engines;
|
||||||
|
++auto_engines)
|
||||||
|
{
|
||||||
|
void *hton= plugin_hton(*auto_engines);
|
||||||
|
char buf[FN_REFLEN+1];
|
||||||
|
LEX_STRING table_name;
|
||||||
|
char *p;
|
||||||
|
rpl_slave_state::gtid_pos_table *entry, **next_ptr;
|
||||||
|
|
||||||
|
/* See if this engine is already in the list. */
|
||||||
|
next_ptr= list_ptr;
|
||||||
|
entry= *list_ptr;
|
||||||
|
while (entry)
|
||||||
|
{
|
||||||
|
if (entry->table_hton == hton)
|
||||||
|
break;
|
||||||
|
next_ptr= &entry->next;
|
||||||
|
entry= entry->next;
|
||||||
|
}
|
||||||
|
if (entry)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Add an auto-create entry for this engine at end of list. */
|
||||||
|
p= strmake(buf, rpl_gtid_slave_state_table_name.str, FN_REFLEN);
|
||||||
|
p= strmake(p, "_", FN_REFLEN - (p - buf));
|
||||||
|
p= strmake(p, plugin_name(*auto_engines)->str, FN_REFLEN - (p - buf));
|
||||||
|
table_name.str= buf;
|
||||||
|
table_name.length= p - buf;
|
||||||
|
entry= rpl_global_gtid_slave_state->alloc_gtid_pos_table
|
||||||
|
(&table_name, hton, rpl_slave_state::GTID_POS_AUTO_CREATE);
|
||||||
|
if (!entry)
|
||||||
|
{
|
||||||
|
err= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*next_ptr= entry;
|
||||||
|
}
|
||||||
|
mysql_mutex_unlock(&LOCK_global_system_variables);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
load_gtid_state_cb(THD *thd, LEX_STRING *table_name, void *arg)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
load_gtid_state_cb_data *data= static_cast<load_gtid_state_cb_data *>(arg);
|
||||||
|
void *hton;
|
||||||
|
|
||||||
|
if ((err= scan_one_gtid_slave_pos_table(thd, data->hash, data->array,
|
||||||
|
table_name, &hton)))
|
||||||
|
return err;
|
||||||
|
return process_gtid_pos_table(thd, table_name, hton, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
rpl_load_gtid_slave_state(THD *thd)
|
||||||
|
{
|
||||||
|
bool array_inited= false;
|
||||||
|
struct gtid_pos_element tmp_entry, *entry;
|
||||||
|
HASH hash;
|
||||||
|
DYNAMIC_ARRAY array;
|
||||||
|
int err= 0;
|
||||||
|
uint32 i;
|
||||||
|
load_gtid_state_cb_data cb_data;
|
||||||
|
DBUG_ENTER("rpl_load_gtid_slave_state");
|
||||||
|
|
||||||
|
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
bool loaded= rpl_global_gtid_slave_state->loaded;
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
if (loaded)
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
cb_data.table_list= NULL;
|
||||||
|
cb_data.default_entry= NULL;
|
||||||
|
my_hash_init(&hash, &my_charset_bin, 32,
|
||||||
|
offsetof(gtid_pos_element, gtid) + offsetof(rpl_gtid, domain_id),
|
||||||
|
sizeof(uint32), NULL, my_free, HASH_UNIQUE);
|
||||||
|
if ((err= my_init_dynamic_array(&array, sizeof(gtid_pos_element), 0, 0, MYF(0))))
|
||||||
|
goto end;
|
||||||
|
array_inited= true;
|
||||||
|
|
||||||
|
cb_data.hash = &hash;
|
||||||
|
cb_data.array = &array;
|
||||||
|
if ((err= scan_all_gtid_slave_pos_table(thd, load_gtid_state_cb, &cb_data)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (!cb_data.default_entry)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If the mysql.gtid_slave_pos table does not exist, but at least one other
|
||||||
|
table is available, arbitrarily pick the first in the list to use as
|
||||||
|
default.
|
||||||
|
*/
|
||||||
|
cb_data.default_entry= cb_data.table_list;
|
||||||
|
}
|
||||||
|
if ((err= gtid_pos_auto_create_tables(&cb_data.table_list)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
if (rpl_global_gtid_slave_state->loaded)
|
||||||
|
{
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cb_data.table_list)
|
||||||
|
{
|
||||||
|
my_error(ER_NO_SUCH_TABLE, MYF(0), "mysql",
|
||||||
|
rpl_gtid_slave_state_table_name.str);
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
err= 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i= 0; i < array.elements; ++i)
|
||||||
|
{
|
||||||
|
get_dynamic(&array, (uchar *)&tmp_entry, i);
|
||||||
|
if ((err= rpl_global_gtid_slave_state->update(tmp_entry.gtid.domain_id,
|
||||||
|
tmp_entry.gtid.server_id,
|
||||||
|
tmp_entry.sub_id,
|
||||||
|
tmp_entry.gtid.seq_no,
|
||||||
|
tmp_entry.hton,
|
||||||
|
NULL)))
|
||||||
|
{
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i= 0; i < hash.records; ++i)
|
||||||
|
{
|
||||||
|
entry= (struct gtid_pos_element *)my_hash_element(&hash, i);
|
||||||
|
if (opt_bin_log &&
|
||||||
|
mysql_bin_log.bump_seq_no_counter_if_needed(entry->gtid.domain_id,
|
||||||
|
entry->gtid.seq_no))
|
||||||
|
{
|
||||||
|
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->set_gtid_pos_tables_list(cb_data.table_list,
|
||||||
|
cb_data.default_entry);
|
||||||
|
cb_data.table_list= NULL;
|
||||||
|
rpl_global_gtid_slave_state->loaded= true;
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
|
||||||
|
end:
|
||||||
if (array_inited)
|
if (array_inited)
|
||||||
delete_dynamic(&array);
|
delete_dynamic(&array);
|
||||||
my_hash_free(&hash);
|
my_hash_free(&hash);
|
||||||
|
if (cb_data.table_list)
|
||||||
|
rpl_global_gtid_slave_state->free_gtid_pos_tables(cb_data.table_list);
|
||||||
DBUG_RETURN(err);
|
DBUG_RETURN(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
find_gtid_pos_tables_cb(THD *thd, LEX_STRING *table_name, void *arg)
|
||||||
|
{
|
||||||
|
load_gtid_state_cb_data *data= static_cast<load_gtid_state_cb_data *>(arg);
|
||||||
|
TABLE_LIST tlist;
|
||||||
|
TABLE *table= NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
thd->reset_for_next_command();
|
||||||
|
tlist.init_one_table(STRING_WITH_LEN("mysql"), table_name->str,
|
||||||
|
table_name->length, NULL, TL_READ);
|
||||||
|
if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0)))
|
||||||
|
goto end;
|
||||||
|
table= tlist.table;
|
||||||
|
|
||||||
|
if ((err= gtid_check_rpl_slave_state_table(table)))
|
||||||
|
goto end;
|
||||||
|
err= process_gtid_pos_table(thd, table_name, table->s->db_type(), data);
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (table)
|
||||||
|
{
|
||||||
|
ha_commit_trans(thd, FALSE);
|
||||||
|
ha_commit_trans(thd, TRUE);
|
||||||
|
close_thread_tables(thd);
|
||||||
|
thd->mdl_context.release_transactional_locks();
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Re-compute the list of available mysql.gtid_slave_posXXX tables.
|
||||||
|
|
||||||
|
This is done at START SLAVE to pick up any newly created tables without
|
||||||
|
requiring server restart.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
find_gtid_slave_pos_tables(THD *thd)
|
||||||
|
{
|
||||||
|
int err= 0;
|
||||||
|
load_gtid_state_cb_data cb_data;
|
||||||
|
uint num_running;
|
||||||
|
|
||||||
|
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
bool loaded= rpl_global_gtid_slave_state->loaded;
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
if (!loaded)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cb_data.table_list= NULL;
|
||||||
|
cb_data.default_entry= NULL;
|
||||||
|
if ((err= scan_all_gtid_slave_pos_table(thd, find_gtid_pos_tables_cb, &cb_data)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (!cb_data.table_list)
|
||||||
|
{
|
||||||
|
my_error(ER_NO_SUCH_TABLE, MYF(0), "mysql",
|
||||||
|
rpl_gtid_slave_state_table_name.str);
|
||||||
|
err= 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (!cb_data.default_entry)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If the mysql.gtid_slave_pos table does not exist, but at least one other
|
||||||
|
table is available, arbitrarily pick the first in the list to use as
|
||||||
|
default.
|
||||||
|
*/
|
||||||
|
cb_data.default_entry= cb_data.table_list;
|
||||||
|
}
|
||||||
|
if ((err= gtid_pos_auto_create_tables(&cb_data.table_list)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
mysql_mutex_lock(&LOCK_active_mi);
|
||||||
|
num_running= any_slave_sql_running(true);
|
||||||
|
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
if (num_running <= 1)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If no slave is running now, the count will be 1, since this SQL thread
|
||||||
|
which is starting is included in the count. In this case, we can safely
|
||||||
|
replace the list, no-one can be trying to read it without lock.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(num_running == 1);
|
||||||
|
rpl_global_gtid_slave_state->set_gtid_pos_tables_list(cb_data.table_list,
|
||||||
|
cb_data.default_entry);
|
||||||
|
cb_data.table_list= NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If there are SQL threads running, we cannot safely remove the old list.
|
||||||
|
However we can add new entries, and warn about any tables that
|
||||||
|
disappeared, but may still be visible to running SQL threads.
|
||||||
|
*/
|
||||||
|
rpl_slave_state::gtid_pos_table *old_entry, *new_entry, **next_ptr_ptr;
|
||||||
|
|
||||||
|
old_entry= (rpl_slave_state::gtid_pos_table *)
|
||||||
|
rpl_global_gtid_slave_state->gtid_pos_tables;
|
||||||
|
while (old_entry)
|
||||||
|
{
|
||||||
|
new_entry= cb_data.table_list;
|
||||||
|
while (new_entry)
|
||||||
|
{
|
||||||
|
if (new_entry->table_hton == old_entry->table_hton)
|
||||||
|
break;
|
||||||
|
new_entry= new_entry->next;
|
||||||
|
}
|
||||||
|
if (!new_entry)
|
||||||
|
sql_print_warning("The table mysql.%s was removed. "
|
||||||
|
"This change will not take full effect "
|
||||||
|
"until all SQL threads have been restarted",
|
||||||
|
old_entry->table_name.str);
|
||||||
|
old_entry= old_entry->next;
|
||||||
|
}
|
||||||
|
next_ptr_ptr= &cb_data.table_list;
|
||||||
|
new_entry= cb_data.table_list;
|
||||||
|
while (new_entry)
|
||||||
|
{
|
||||||
|
/* Check if we already have a table with this storage engine. */
|
||||||
|
old_entry= (rpl_slave_state::gtid_pos_table *)
|
||||||
|
rpl_global_gtid_slave_state->gtid_pos_tables;
|
||||||
|
while (old_entry)
|
||||||
|
{
|
||||||
|
if (new_entry->table_hton == old_entry->table_hton)
|
||||||
|
break;
|
||||||
|
old_entry= old_entry->next;
|
||||||
|
}
|
||||||
|
if (old_entry)
|
||||||
|
{
|
||||||
|
/* This new_entry is already available in the list. */
|
||||||
|
next_ptr_ptr= &new_entry->next;
|
||||||
|
new_entry= new_entry->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Move this new_entry to the list. */
|
||||||
|
rpl_slave_state::gtid_pos_table *next= new_entry->next;
|
||||||
|
rpl_global_gtid_slave_state->add_gtid_pos_table(new_entry);
|
||||||
|
*next_ptr_ptr= next;
|
||||||
|
new_entry= next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
mysql_mutex_unlock(&LOCK_active_mi);
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (cb_data.table_list)
|
||||||
|
rpl_global_gtid_slave_state->free_gtid_pos_tables(cb_data.table_list);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
rpl_group_info::reinit(Relay_log_info *rli)
|
rpl_group_info::reinit(Relay_log_info *rli)
|
||||||
{
|
{
|
||||||
|
@ -959,6 +959,7 @@ extern struct rpl_slave_state *rpl_global_gtid_slave_state;
|
|||||||
extern gtid_waiting rpl_global_gtid_waiting;
|
extern gtid_waiting rpl_global_gtid_waiting;
|
||||||
|
|
||||||
int rpl_load_gtid_slave_state(THD *thd);
|
int rpl_load_gtid_slave_state(THD *thd);
|
||||||
|
int find_gtid_slave_pos_tables(THD *thd);
|
||||||
int event_group_new_gtid(rpl_group_info *rgi, Gtid_log_event *gev);
|
int event_group_new_gtid(rpl_group_info *rgi, Gtid_log_event *gev);
|
||||||
void delete_or_keep_event_post_apply(rpl_group_info *rgi,
|
void delete_or_keep_event_post_apply(rpl_group_info *rgi,
|
||||||
Log_event_type typ, Log_event *ev);
|
Log_event_type typ, Log_event *ev);
|
||||||
|
219
sql/set_var.cc
219
sql/set_var.cc
@ -1293,3 +1293,222 @@ enum sys_var::where get_sys_var_value_origin(void *ptr)
|
|||||||
return sys_var::CONFIG;
|
return sys_var::CONFIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find the next item in string of comma-separated items.
|
||||||
|
END_POS points at the end of the string.
|
||||||
|
ITEM_START and ITEM_END return the limits of the next item.
|
||||||
|
Returns true while items are available, false at the end.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
engine_list_next_item(const char **pos, const char *end_pos,
|
||||||
|
const char **item_start, const char **item_end)
|
||||||
|
{
|
||||||
|
if (*pos >= end_pos)
|
||||||
|
return false;
|
||||||
|
*item_start= *pos;
|
||||||
|
while (*pos < end_pos && **pos != ',')
|
||||||
|
++*pos;
|
||||||
|
*item_end= *pos;
|
||||||
|
++*pos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
resolve_engine_list_item(THD *thd, plugin_ref *list, uint32 *idx,
|
||||||
|
const char *pos, const char *pos_end,
|
||||||
|
bool error_on_unknown_engine, bool temp_copy)
|
||||||
|
{
|
||||||
|
LEX_STRING item_str;
|
||||||
|
plugin_ref ref;
|
||||||
|
uint32_t i;
|
||||||
|
THD *thd_or_null = (temp_copy ? thd : NULL);
|
||||||
|
|
||||||
|
item_str.str= const_cast<char*>(pos);
|
||||||
|
item_str.length= pos_end-pos;
|
||||||
|
ref= ha_resolve_by_name(thd_or_null, &item_str, false);
|
||||||
|
if (!ref)
|
||||||
|
{
|
||||||
|
if (error_on_unknown_engine)
|
||||||
|
{
|
||||||
|
ErrConvString err(pos, pos_end-pos, system_charset_info);
|
||||||
|
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Ignore duplicates, like --plugin-load does. */
|
||||||
|
for (i= 0; i < *idx; ++i)
|
||||||
|
{
|
||||||
|
if (plugin_hton(list[i]) == plugin_hton(ref))
|
||||||
|
{
|
||||||
|
if (!temp_copy)
|
||||||
|
plugin_unlock(NULL, ref);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list[*idx]= ref;
|
||||||
|
++*idx;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Helper for class Sys_var_pluginlist.
|
||||||
|
Resolve a comma-separated list of storage engine names to a null-terminated
|
||||||
|
array of plugin_ref.
|
||||||
|
|
||||||
|
If TEMP_COPY is true, a THD must be given as well. In this case, the
|
||||||
|
allocated memory and locked plugins are registered in the THD and will
|
||||||
|
be freed / unlocked automatically. If TEMP_COPY is true, THD can be
|
||||||
|
passed as NULL, and resources must be freed explicitly later with
|
||||||
|
free_engine_list().
|
||||||
|
*/
|
||||||
|
plugin_ref *
|
||||||
|
resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len,
|
||||||
|
bool error_on_unknown_engine, bool temp_copy)
|
||||||
|
{
|
||||||
|
uint32 count, idx;
|
||||||
|
const char *pos, *item_start, *item_end;
|
||||||
|
const char *str_arg_end= str_arg + str_arg_len;
|
||||||
|
plugin_ref *res;
|
||||||
|
|
||||||
|
count= 0;
|
||||||
|
pos= str_arg;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!engine_list_next_item(&pos, str_arg_end, &item_start, &item_end))
|
||||||
|
break;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp_copy)
|
||||||
|
res= (plugin_ref *)thd->calloc((count+1)*sizeof(*res));
|
||||||
|
else
|
||||||
|
res= (plugin_ref *)my_malloc((count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME));
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*res)));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx= 0;
|
||||||
|
pos= str_arg;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!engine_list_next_item(&pos, str_arg_end, &item_start, &item_end))
|
||||||
|
break;
|
||||||
|
DBUG_ASSERT(idx < count);
|
||||||
|
if (idx >= count)
|
||||||
|
break;
|
||||||
|
if (resolve_engine_list_item(thd, res, &idx, item_start, item_end,
|
||||||
|
error_on_unknown_engine, temp_copy))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (!temp_copy)
|
||||||
|
free_engine_list(res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
free_engine_list(plugin_ref *list)
|
||||||
|
{
|
||||||
|
plugin_ref *p;
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return;
|
||||||
|
for (p= list; *p; ++p)
|
||||||
|
plugin_unlock(NULL, *p);
|
||||||
|
my_free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
plugin_ref *
|
||||||
|
copy_engine_list(plugin_ref *list)
|
||||||
|
{
|
||||||
|
plugin_ref *p;
|
||||||
|
uint32 count, i;
|
||||||
|
|
||||||
|
for (p= list, count= 0; *p; ++p, ++count)
|
||||||
|
;
|
||||||
|
p= (plugin_ref *)my_malloc((count+1)*sizeof(*p), MYF(0));
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*p)));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i= 0; i < count; ++i)
|
||||||
|
p[i]= my_plugin_lock(NULL, list[i]);
|
||||||
|
p[i] = NULL;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a temporary copy of an engine list. The memory will be freed
|
||||||
|
(and the plugins unlocked) automatically, on the passed THD.
|
||||||
|
*/
|
||||||
|
plugin_ref *
|
||||||
|
temp_copy_engine_list(THD *thd, plugin_ref *list)
|
||||||
|
{
|
||||||
|
plugin_ref *p;
|
||||||
|
uint32 count, i;
|
||||||
|
|
||||||
|
for (p= list, count= 0; *p; ++p, ++count)
|
||||||
|
;
|
||||||
|
p= (plugin_ref *)thd->alloc((count+1)*sizeof(*p));
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*p)));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i= 0; i < count; ++i)
|
||||||
|
p[i]= my_plugin_lock(thd, list[i]);
|
||||||
|
p[i] = NULL;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
pretty_print_engine_list(THD *thd, plugin_ref *list)
|
||||||
|
{
|
||||||
|
plugin_ref *p;
|
||||||
|
size_t size;
|
||||||
|
char *buf, *pos;
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return thd->strmake("", 0);
|
||||||
|
|
||||||
|
size= 0;
|
||||||
|
for (p= list; *p; ++p)
|
||||||
|
size+= plugin_name(*p)->length + 1;
|
||||||
|
buf= static_cast<char *>(thd->alloc(size));
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
pos= buf;
|
||||||
|
for (p= list; *p; ++p)
|
||||||
|
{
|
||||||
|
LEX_STRING *name;
|
||||||
|
size_t remain;
|
||||||
|
|
||||||
|
remain= buf + size - pos;
|
||||||
|
DBUG_ASSERT(remain > 0);
|
||||||
|
if (remain <= 1)
|
||||||
|
break;
|
||||||
|
if (pos != buf)
|
||||||
|
{
|
||||||
|
pos= strmake(pos, ",", remain-1);
|
||||||
|
--remain;
|
||||||
|
}
|
||||||
|
name= plugin_name(*p);
|
||||||
|
pos= strmake(pos, name->str, MY_MIN(name->length, remain-1));
|
||||||
|
}
|
||||||
|
*pos= '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
@ -286,6 +286,7 @@ public:
|
|||||||
longlong longlong_value; ///< for signed integer
|
longlong longlong_value; ///< for signed integer
|
||||||
double double_value; ///< for Sys_var_double
|
double double_value; ///< for Sys_var_double
|
||||||
plugin_ref plugin; ///< for Sys_var_plugin
|
plugin_ref plugin; ///< for Sys_var_plugin
|
||||||
|
plugin_ref *plugins; ///< for Sys_var_pluginlist
|
||||||
Time_zone *time_zone; ///< for Sys_var_tz
|
Time_zone *time_zone; ///< for Sys_var_tz
|
||||||
LEX_STRING string_value; ///< for Sys_var_charptr and others
|
LEX_STRING string_value; ///< for Sys_var_charptr and others
|
||||||
const void *ptr; ///< for Sys_var_struct
|
const void *ptr; ///< for Sys_var_struct
|
||||||
@ -424,6 +425,12 @@ int sys_var_init();
|
|||||||
uint sys_var_elements();
|
uint sys_var_elements();
|
||||||
int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags);
|
int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags);
|
||||||
void sys_var_end(void);
|
void sys_var_end(void);
|
||||||
|
plugin_ref *resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len,
|
||||||
|
bool error_on_unknown_engine, bool temp_copy);
|
||||||
|
void free_engine_list(plugin_ref *list);
|
||||||
|
plugin_ref *copy_engine_list(plugin_ref *list);
|
||||||
|
plugin_ref *temp_copy_engine_list(THD *thd, plugin_ref *list);
|
||||||
|
char *pretty_print_engine_list(THD *thd, plugin_ref *list);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
226
sql/slave.cc
226
sql/slave.cc
@ -60,6 +60,7 @@
|
|||||||
#include "rpl_tblmap.h"
|
#include "rpl_tblmap.h"
|
||||||
#include "debug_sync.h"
|
#include "debug_sync.h"
|
||||||
#include "rpl_parallel.h"
|
#include "rpl_parallel.h"
|
||||||
|
#include "sql_show.h"
|
||||||
|
|
||||||
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
|
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
|
||||||
|
|
||||||
@ -279,15 +280,180 @@ static void init_slave_psi_keys(void)
|
|||||||
#endif /* HAVE_PSI_INTERFACE */
|
#endif /* HAVE_PSI_INTERFACE */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note: This definition needs to be kept in sync with the one in
|
||||||
|
mysql_system_tables.sql which is used by mysql_create_db.
|
||||||
|
*/
|
||||||
|
static const char gtid_pos_table_definition1[]=
|
||||||
|
"CREATE TABLE ";
|
||||||
|
static const char gtid_pos_table_definition2[]=
|
||||||
|
" (domain_id INT UNSIGNED NOT NULL, "
|
||||||
|
"sub_id BIGINT UNSIGNED NOT NULL, "
|
||||||
|
"server_id INT UNSIGNED NOT NULL, "
|
||||||
|
"seq_no BIGINT UNSIGNED NOT NULL, "
|
||||||
|
"PRIMARY KEY (domain_id, sub_id)) CHARSET=latin1 "
|
||||||
|
"COMMENT='Replication slave GTID position' "
|
||||||
|
"ENGINE=";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Build a query string
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_<engine> ... ENGINE=<engine>
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
build_gtid_pos_create_query(THD *thd, String *query,
|
||||||
|
LEX_STRING *table_name,
|
||||||
|
LEX_STRING *engine_name)
|
||||||
|
{
|
||||||
|
bool err= false;
|
||||||
|
err|= query->append(gtid_pos_table_definition1);
|
||||||
|
err|= append_identifier(thd, query, table_name->str, table_name->length);
|
||||||
|
err|= query->append(gtid_pos_table_definition2);
|
||||||
|
err|= append_identifier(thd, query, engine_name->str, engine_name->length);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
gtid_pos_table_creation(THD *thd, plugin_ref engine, LEX_STRING *table_name)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
StringBuffer<sizeof(gtid_pos_table_definition1) +
|
||||||
|
sizeof(gtid_pos_table_definition1) +
|
||||||
|
2*FN_REFLEN> query;
|
||||||
|
|
||||||
|
if (build_gtid_pos_create_query(thd, &query, table_name, plugin_name(engine)))
|
||||||
|
{
|
||||||
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
thd->set_db("mysql", 5);
|
||||||
|
thd->clear_error();
|
||||||
|
ulonglong thd_saved_option= thd->variables.option_bits;
|
||||||
|
/* This query shuold not be binlogged. */
|
||||||
|
thd->variables.option_bits&= ~(ulonglong)OPTION_BIN_LOG;
|
||||||
|
thd->set_query_and_id(query.c_ptr(), query.length(), thd->charset(),
|
||||||
|
next_query_id());
|
||||||
|
Parser_state parser_state;
|
||||||
|
err= parser_state.init(thd, thd->query(), thd->query_length());
|
||||||
|
if (err)
|
||||||
|
goto end;
|
||||||
|
mysql_parse(thd, thd->query(), thd->query_length(), &parser_state,
|
||||||
|
FALSE, FALSE);
|
||||||
|
if (thd->is_error())
|
||||||
|
err= 1;
|
||||||
|
end:
|
||||||
|
thd->variables.option_bits= thd_saved_option;
|
||||||
|
thd->reset_query();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_gtid_pos_auto_create_request(THD *thd, void *hton)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
plugin_ref engine= NULL, *auto_engines;
|
||||||
|
rpl_slave_state::gtid_pos_table *entry;
|
||||||
|
StringBuffer<FN_REFLEN> loc_table_name;
|
||||||
|
LEX_STRING table_name;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check that the plugin is still in @@gtid_pos_auto_engines, and lock
|
||||||
|
it.
|
||||||
|
*/
|
||||||
|
mysql_mutex_lock(&LOCK_global_system_variables);
|
||||||
|
engine= NULL;
|
||||||
|
for (auto_engines= opt_gtid_pos_auto_plugins;
|
||||||
|
auto_engines && *auto_engines;
|
||||||
|
++auto_engines)
|
||||||
|
{
|
||||||
|
if (plugin_hton(*auto_engines) == hton)
|
||||||
|
{
|
||||||
|
engine= my_plugin_lock(NULL, *auto_engines);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mysql_mutex_unlock(&LOCK_global_system_variables);
|
||||||
|
if (!engine)
|
||||||
|
{
|
||||||
|
/* The engine is gone from @@gtid_pos_auto_engines, so no action. */
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the entry for the table to auto-create. */
|
||||||
|
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
entry= (rpl_slave_state::gtid_pos_table *)
|
||||||
|
rpl_global_gtid_slave_state->gtid_pos_tables;
|
||||||
|
while (entry)
|
||||||
|
{
|
||||||
|
if (entry->table_hton == hton &&
|
||||||
|
entry->state == rpl_slave_state::GTID_POS_CREATE_REQUESTED)
|
||||||
|
break;
|
||||||
|
entry= entry->next;
|
||||||
|
}
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
entry->state = rpl_slave_state::GTID_POS_CREATE_IN_PROGRESS;
|
||||||
|
err= loc_table_name.append(entry->table_name.str, entry->table_name.length);
|
||||||
|
}
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
if (!entry)
|
||||||
|
goto end;
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
sql_print_error("Out of memory while trying to auto-create GTID position table");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
table_name.str= loc_table_name.c_ptr_safe();
|
||||||
|
table_name.length= loc_table_name.length();
|
||||||
|
|
||||||
|
err= gtid_pos_table_creation(thd, engine, &table_name);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
sql_print_error("Error auto-creating GTID position table `mysql.%s`: %s Error_code: %d",
|
||||||
|
table_name.str, thd->get_stmt_da()->message(),
|
||||||
|
thd->get_stmt_da()->sql_errno());
|
||||||
|
thd->clear_error();
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now enable the entry for the auto-created table. */
|
||||||
|
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
entry= (rpl_slave_state::gtid_pos_table *)
|
||||||
|
rpl_global_gtid_slave_state->gtid_pos_tables;
|
||||||
|
while (entry)
|
||||||
|
{
|
||||||
|
if (entry->table_hton == hton &&
|
||||||
|
entry->state == rpl_slave_state::GTID_POS_CREATE_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
entry->state= rpl_slave_state::GTID_POS_AVAILABLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
entry= entry->next;
|
||||||
|
}
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (engine)
|
||||||
|
plugin_unlock(NULL, engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool slave_background_thread_running;
|
static bool slave_background_thread_running;
|
||||||
static bool slave_background_thread_stop;
|
static bool slave_background_thread_stop;
|
||||||
static bool slave_background_thread_gtid_loaded;
|
static bool slave_background_thread_gtid_loaded;
|
||||||
|
|
||||||
struct slave_background_kill_t {
|
static struct slave_background_kill_t {
|
||||||
slave_background_kill_t *next;
|
slave_background_kill_t *next;
|
||||||
THD *to_kill;
|
THD *to_kill;
|
||||||
} *slave_background_kill_list;
|
} *slave_background_kill_list;
|
||||||
|
|
||||||
|
static struct slave_background_gtid_pos_create_t {
|
||||||
|
slave_background_gtid_pos_create_t *next;
|
||||||
|
void *hton;
|
||||||
|
} *slave_background_gtid_pos_create_list;
|
||||||
|
|
||||||
|
|
||||||
pthread_handler_t
|
pthread_handler_t
|
||||||
handle_slave_background(void *arg __attribute__((unused)))
|
handle_slave_background(void *arg __attribute__((unused)))
|
||||||
@ -321,6 +487,7 @@ handle_slave_background(void *arg __attribute__((unused)))
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
slave_background_kill_t *kill_list;
|
slave_background_kill_t *kill_list;
|
||||||
|
slave_background_gtid_pos_create_t *create_list;
|
||||||
|
|
||||||
thd->ENTER_COND(&COND_slave_background, &LOCK_slave_background,
|
thd->ENTER_COND(&COND_slave_background, &LOCK_slave_background,
|
||||||
&stage_slave_background_wait_request,
|
&stage_slave_background_wait_request,
|
||||||
@ -329,12 +496,14 @@ handle_slave_background(void *arg __attribute__((unused)))
|
|||||||
{
|
{
|
||||||
stop= abort_loop || thd->killed || slave_background_thread_stop;
|
stop= abort_loop || thd->killed || slave_background_thread_stop;
|
||||||
kill_list= slave_background_kill_list;
|
kill_list= slave_background_kill_list;
|
||||||
if (stop || kill_list)
|
create_list= slave_background_gtid_pos_create_list;
|
||||||
|
if (stop || kill_list || create_list)
|
||||||
break;
|
break;
|
||||||
mysql_cond_wait(&COND_slave_background, &LOCK_slave_background);
|
mysql_cond_wait(&COND_slave_background, &LOCK_slave_background);
|
||||||
}
|
}
|
||||||
|
|
||||||
slave_background_kill_list= NULL;
|
slave_background_kill_list= NULL;
|
||||||
|
slave_background_gtid_pos_create_list= NULL;
|
||||||
thd->EXIT_COND(&old_stage);
|
thd->EXIT_COND(&old_stage);
|
||||||
|
|
||||||
while (kill_list)
|
while (kill_list)
|
||||||
@ -353,6 +522,16 @@ handle_slave_background(void *arg __attribute__((unused)))
|
|||||||
mysql_mutex_unlock(&to_kill->LOCK_wakeup_ready);
|
mysql_mutex_unlock(&to_kill->LOCK_wakeup_ready);
|
||||||
my_free(p);
|
my_free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (create_list)
|
||||||
|
{
|
||||||
|
slave_background_gtid_pos_create_t *next= create_list->next;
|
||||||
|
void *hton= create_list->hton;
|
||||||
|
handle_gtid_pos_auto_create_request(thd, hton);
|
||||||
|
my_free(create_list);
|
||||||
|
create_list= next;
|
||||||
|
}
|
||||||
|
|
||||||
mysql_mutex_lock(&LOCK_slave_background);
|
mysql_mutex_lock(&LOCK_slave_background);
|
||||||
} while (!stop);
|
} while (!stop);
|
||||||
|
|
||||||
@ -391,6 +570,41 @@ slave_background_kill_request(THD *to_kill)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function must only be called from a slave SQL thread (or worker thread),
|
||||||
|
to ensure that the table_entry will not go away before we can lock the
|
||||||
|
LOCK_slave_state.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
slave_background_gtid_pos_create_request(
|
||||||
|
rpl_slave_state::gtid_pos_table *table_entry)
|
||||||
|
{
|
||||||
|
slave_background_gtid_pos_create_t *p;
|
||||||
|
|
||||||
|
if (table_entry->state != rpl_slave_state::GTID_POS_AUTO_CREATE)
|
||||||
|
return;
|
||||||
|
p= (slave_background_gtid_pos_create_t *)my_malloc(sizeof(*p), MYF(MY_WME));
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
if (table_entry->state != rpl_slave_state::GTID_POS_AUTO_CREATE)
|
||||||
|
{
|
||||||
|
my_free(p);
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
table_entry->state= rpl_slave_state::GTID_POS_CREATE_REQUESTED;
|
||||||
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
||||||
|
|
||||||
|
p->hton= table_entry->table_hton;
|
||||||
|
mysql_mutex_lock(&LOCK_slave_background);
|
||||||
|
p->next= slave_background_gtid_pos_create_list;
|
||||||
|
slave_background_gtid_pos_create_list= p;
|
||||||
|
mysql_cond_signal(&COND_slave_background);
|
||||||
|
mysql_mutex_unlock(&LOCK_slave_background);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start the slave background thread.
|
Start the slave background thread.
|
||||||
|
|
||||||
@ -5065,6 +5279,14 @@ pthread_handler_t handle_slave_sql(void *arg)
|
|||||||
if (mi->using_gtid != Master_info::USE_GTID_NO || opt_gtid_strict_mode)
|
if (mi->using_gtid != Master_info::USE_GTID_NO || opt_gtid_strict_mode)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
/* Re-load the set of mysql.gtid_slave_posXXX tables available. */
|
||||||
|
if (find_gtid_slave_pos_tables(thd))
|
||||||
|
{
|
||||||
|
rli->report(ERROR_LEVEL, thd->get_stmt_da()->sql_errno(), NULL,
|
||||||
|
"Error processing replication GTID position tables: %s",
|
||||||
|
thd->get_stmt_da()->message());
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/* execute init_slave variable */
|
/* execute init_slave variable */
|
||||||
if (opt_init_slave.length)
|
if (opt_init_slave.length)
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "my_list.h"
|
#include "my_list.h"
|
||||||
#include "rpl_filter.h"
|
#include "rpl_filter.h"
|
||||||
#include "rpl_tblmap.h"
|
#include "rpl_tblmap.h"
|
||||||
|
#include "rpl_gtid.h"
|
||||||
|
|
||||||
#define SLAVE_NET_TIMEOUT 60
|
#define SLAVE_NET_TIMEOUT 60
|
||||||
|
|
||||||
@ -268,6 +269,8 @@ void slave_output_error_info(rpl_group_info *rgi, THD *thd);
|
|||||||
pthread_handler_t handle_slave_sql(void *arg);
|
pthread_handler_t handle_slave_sql(void *arg);
|
||||||
bool net_request_file(NET* net, const char* fname);
|
bool net_request_file(NET* net, const char* fname);
|
||||||
void slave_background_kill_request(THD *to_kill);
|
void slave_background_kill_request(THD *to_kill);
|
||||||
|
void slave_background_gtid_pos_create_request
|
||||||
|
(rpl_slave_state::gtid_pos_table *table_entry);
|
||||||
|
|
||||||
extern bool volatile abort_loop;
|
extern bool volatile abort_loop;
|
||||||
extern Master_info *active_mi; /* active_mi for multi-master */
|
extern Master_info *active_mi; /* active_mi for multi-master */
|
||||||
|
@ -941,6 +941,10 @@ SHOW_COMP_OPTION plugin_status(const char *name, size_t len, int type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
If LEX is passed non-NULL, an automatic unlock of the plugin will happen
|
||||||
|
in the LEX destructor.
|
||||||
|
*/
|
||||||
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc)
|
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc)
|
||||||
{
|
{
|
||||||
st_plugin_int *pi= plugin_ref_to_int(rc);
|
st_plugin_int *pi= plugin_ref_to_int(rc);
|
||||||
@ -984,6 +988,16 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Notes on lifetime:
|
||||||
|
|
||||||
|
If THD is passed as non-NULL (and with a non-NULL thd->lex), an entry is made
|
||||||
|
in the thd->lex which will cause an automatic unlock of the plugin in the LEX
|
||||||
|
destructor. In this case, no manual unlock must be done.
|
||||||
|
|
||||||
|
Otherwise, when passing a NULL THD, the caller must arrange that plugin
|
||||||
|
unlock happens later.
|
||||||
|
*/
|
||||||
plugin_ref plugin_lock(THD *thd, plugin_ref ptr)
|
plugin_ref plugin_lock(THD *thd, plugin_ref ptr)
|
||||||
{
|
{
|
||||||
LEX *lex= thd ? thd->lex : 0;
|
LEX *lex= thd ? thd->lex : 0;
|
||||||
@ -1020,6 +1034,16 @@ plugin_ref plugin_lock(THD *thd, plugin_ref ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Notes on lifetime:
|
||||||
|
|
||||||
|
If THD is passed as non-NULL (and with a non-NULL thd->lex), an entry is made
|
||||||
|
in the thd->lex which will cause an automatic unlock of the plugin in the LEX
|
||||||
|
destructor. In this case, no manual unlock must be done.
|
||||||
|
|
||||||
|
Otherwise, when passing a NULL THD, the caller must arrange that plugin
|
||||||
|
unlock happens later.
|
||||||
|
*/
|
||||||
plugin_ref plugin_lock_by_name(THD *thd, const LEX_CSTRING *name, int type)
|
plugin_ref plugin_lock_by_name(THD *thd, const LEX_CSTRING *name, int type)
|
||||||
{
|
{
|
||||||
LEX *lex= thd ? thd->lex : 0;
|
LEX *lex= thd ? thd->lex : 0;
|
||||||
@ -1935,6 +1959,12 @@ void plugin_shutdown(void)
|
|||||||
|
|
||||||
if (initialized)
|
if (initialized)
|
||||||
{
|
{
|
||||||
|
if (opt_gtid_pos_auto_plugins)
|
||||||
|
{
|
||||||
|
free_engine_list(opt_gtid_pos_auto_plugins);
|
||||||
|
opt_gtid_pos_auto_plugins= NULL;
|
||||||
|
}
|
||||||
|
|
||||||
mysql_mutex_lock(&LOCK_plugin);
|
mysql_mutex_lock(&LOCK_plugin);
|
||||||
|
|
||||||
reap_needed= true;
|
reap_needed= true;
|
||||||
|
@ -3556,6 +3556,45 @@ static Sys_var_plugin Sys_enforce_storage_engine(
|
|||||||
NO_CMD_LINE, MYSQL_STORAGE_ENGINE_PLUGIN,
|
NO_CMD_LINE, MYSQL_STORAGE_ENGINE_PLUGIN,
|
||||||
DEFAULT(&enforced_storage_engine), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super));
|
DEFAULT(&enforced_storage_engine), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super));
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_REPLICATION
|
||||||
|
/*
|
||||||
|
Check
|
||||||
|
1. Value for gtid_pos_auto_engines is not NULL.
|
||||||
|
2. No slave SQL thread is running.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
check_gtid_pos_auto_engines(sys_var *self, THD *thd, set_var *var)
|
||||||
|
{
|
||||||
|
bool running;
|
||||||
|
bool err= false;
|
||||||
|
|
||||||
|
DBUG_ASSERT(var->type == OPT_GLOBAL);
|
||||||
|
if (var->value && var->value->is_null())
|
||||||
|
err= true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
running= give_error_if_slave_running(false);
|
||||||
|
if (running)
|
||||||
|
err= true;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Sys_var_pluginlist Sys_gtid_pos_auto_engines(
|
||||||
|
"gtid_pos_auto_engines",
|
||||||
|
"List of engines for which to automatically create a "
|
||||||
|
"mysql.gtid_slave_pos_ENGINE table, if a transaction using that engine "
|
||||||
|
"is replicated. This can be used to avoid introducing cross-engine "
|
||||||
|
"transactions, if engines are used different from that used by table "
|
||||||
|
"mysql.gtid_slave_pos",
|
||||||
|
GLOBAL_VAR(opt_gtid_pos_auto_plugins), NO_CMD_LINE,
|
||||||
|
DEFAULT(>id_pos_auto_engines),
|
||||||
|
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_gtid_pos_auto_engines));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(ENABLED_DEBUG_SYNC)
|
#if defined(ENABLED_DEBUG_SYNC)
|
||||||
/*
|
/*
|
||||||
Variable can be set for the session only.
|
Variable can be set for the session only.
|
||||||
|
110
sql/sys_vars.ic
110
sql/sys_vars.ic
@ -1535,6 +1535,116 @@ public:
|
|||||||
{ return valptr(thd, get_default(thd)); }
|
{ return valptr(thd, get_default(thd)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Class for variables that containg a list of plugins.
|
||||||
|
Currently this is used only for @@gtid_pos_auto_create_engines
|
||||||
|
|
||||||
|
Backing store: plugin_ref
|
||||||
|
|
||||||
|
@note
|
||||||
|
Currently this is only used for storage engine type plugins, and thus only
|
||||||
|
storage engine type plugin is implemented. It could be extended to other
|
||||||
|
plugin types later if needed, similar to Sys_var_plugin.
|
||||||
|
|
||||||
|
These variables don't support command-line equivalents, any such
|
||||||
|
command-line options should be added manually to my_long_options in mysqld.cc
|
||||||
|
|
||||||
|
Note on lifetimes of resources allocated: We allocate a zero-terminated array
|
||||||
|
of plugin_ref*, and lock the contained plugins. The list in the global
|
||||||
|
variable must be freed (with free_engine_list()). However, the way Sys_var
|
||||||
|
works, there is no place to explicitly free other lists, like the one
|
||||||
|
returned from get_default().
|
||||||
|
|
||||||
|
Therefore, the code needs to work with temporary lists, which are
|
||||||
|
registered in the THD to be automatically freed (and plugins similarly
|
||||||
|
automatically unlocked). This is why do_check() allocates a temporary
|
||||||
|
list, from which do_update() then makes a permanent copy.
|
||||||
|
*/
|
||||||
|
class Sys_var_pluginlist: public sys_var
|
||||||
|
{
|
||||||
|
int plugin_type;
|
||||||
|
public:
|
||||||
|
Sys_var_pluginlist(const char *name_arg,
|
||||||
|
const char *comment, int flag_args, ptrdiff_t off, size_t size,
|
||||||
|
CMD_LINE getopt,
|
||||||
|
char **def_val, PolyLock *lock=0,
|
||||||
|
enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
|
||||||
|
on_check_function on_check_func=0,
|
||||||
|
on_update_function on_update_func=0,
|
||||||
|
const char *substitute=0)
|
||||||
|
: sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
|
||||||
|
getopt.arg_type, SHOW_CHAR, (intptr)def_val,
|
||||||
|
lock, binlog_status_arg, on_check_func, on_update_func,
|
||||||
|
substitute)
|
||||||
|
{
|
||||||
|
option.var_type|= GET_STR;
|
||||||
|
SYSVAR_ASSERT(size == sizeof(plugin_ref));
|
||||||
|
SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE
|
||||||
|
}
|
||||||
|
bool do_check(THD *thd, set_var *var)
|
||||||
|
{
|
||||||
|
char buff[STRING_BUFFER_USUAL_SIZE];
|
||||||
|
String str(buff,sizeof(buff), system_charset_info), *res;
|
||||||
|
plugin_ref *plugins;
|
||||||
|
|
||||||
|
if (!(res=var->value->val_str(&str)))
|
||||||
|
plugins= resolve_engine_list(thd, "", 0, true, true);
|
||||||
|
else
|
||||||
|
plugins= resolve_engine_list(thd, res->ptr(), res->length(), true, true);
|
||||||
|
if (!plugins)
|
||||||
|
return true;
|
||||||
|
var->save_result.plugins= plugins;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void do_update(plugin_ref **valptr, plugin_ref* newval)
|
||||||
|
{
|
||||||
|
plugin_ref *oldval= *valptr;
|
||||||
|
*valptr= copy_engine_list(newval);
|
||||||
|
free_engine_list(oldval);
|
||||||
|
}
|
||||||
|
bool session_update(THD *thd, set_var *var)
|
||||||
|
{
|
||||||
|
do_update((plugin_ref**)session_var_ptr(thd),
|
||||||
|
var->save_result.plugins);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool global_update(THD *thd, set_var *var)
|
||||||
|
{
|
||||||
|
do_update((plugin_ref**)global_var_ptr(),
|
||||||
|
var->save_result.plugins);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void session_save_default(THD *thd, set_var *var)
|
||||||
|
{
|
||||||
|
plugin_ref* plugins= global_var(plugin_ref *);
|
||||||
|
var->save_result.plugins= plugins ? temp_copy_engine_list(thd, plugins) : 0;
|
||||||
|
}
|
||||||
|
plugin_ref *get_default(THD *thd)
|
||||||
|
{
|
||||||
|
char *default_value= *reinterpret_cast<char**>(option.def_value);
|
||||||
|
if (!default_value)
|
||||||
|
return 0;
|
||||||
|
return resolve_engine_list(thd, default_value, strlen(default_value),
|
||||||
|
false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void global_save_default(THD *thd, set_var *var)
|
||||||
|
{
|
||||||
|
var->save_result.plugins= get_default(thd);
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar *valptr(THD *thd, plugin_ref *plugins)
|
||||||
|
{
|
||||||
|
return (uchar*)pretty_print_engine_list(thd, plugins);
|
||||||
|
}
|
||||||
|
uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
|
||||||
|
{ return valptr(thd, session_var(thd, plugin_ref*)); }
|
||||||
|
uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
|
||||||
|
{ return valptr(thd, global_var(plugin_ref*)); }
|
||||||
|
uchar *default_value_ptr(THD *thd)
|
||||||
|
{ return valptr(thd, get_default(thd)); }
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(ENABLED_DEBUG_SYNC)
|
#if defined(ENABLED_DEBUG_SYNC)
|
||||||
|
|
||||||
#include "debug_sync.h"
|
#include "debug_sync.h"
|
||||||
|
@ -39,7 +39,9 @@ connection slave;
|
|||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT * FROM t1 FOR UPDATE;
|
SELECT * FROM t1 FOR UPDATE;
|
||||||
a
|
a
|
||||||
|
connection slave1;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
|
connection slave;
|
||||||
SELECT COUNT(*) FROM t2;
|
SELECT COUNT(*) FROM t2;
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
0
|
0
|
||||||
@ -61,8 +63,10 @@ BEGIN;
|
|||||||
SELECT * FROM t1 FOR UPDATE;
|
SELECT * FROM t1 FOR UPDATE;
|
||||||
a
|
a
|
||||||
1
|
1
|
||||||
|
connection slave1;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1205]
|
include/wait_for_slave_sql_error.inc [errno=1205]
|
||||||
|
connection slave;
|
||||||
SELECT COUNT(*) FROM t2;
|
SELECT COUNT(*) FROM t2;
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
0
|
0
|
||||||
@ -92,8 +96,10 @@ SELECT * FROM t1 FOR UPDATE;
|
|||||||
a
|
a
|
||||||
1
|
1
|
||||||
1
|
1
|
||||||
|
connection slave1;
|
||||||
START SLAVE;
|
START SLAVE;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1205]
|
include/wait_for_slave_sql_error.inc [errno=1205]
|
||||||
|
connection slave;
|
||||||
SELECT COUNT(*) FROM t2;
|
SELECT COUNT(*) FROM t2;
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
0
|
0
|
||||||
|
265
storage/tokudb/mysql-test/tokudb_rpl/r/mdev12179.result
Normal file
265
storage/tokudb/mysql-test/tokudb_rpl/r/mdev12179.result
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
include/master-slave.inc
|
||||||
|
[connection master]
|
||||||
|
connection server_2;
|
||||||
|
include/stop_slave.inc
|
||||||
|
CHANGE MASTER TO master_use_gtid=slave_pos;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_innodb LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_innodb ENGINE=InnoDB;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_tokudb LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_tokudb ENGINE=TokuDB;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_myisam_redundant LIKE mysql.gtid_slave_pos;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_innodb_redundant LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_innodb_redundant ENGINE=InnoDB;
|
||||||
|
call mtr.add_suppression("Ignoring redundant table.*since.*has the same storage engine");
|
||||||
|
include/start_slave.inc
|
||||||
|
connection server_1;
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||||
|
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t3 (a INT PRIMARY KEY) ENGINE=TokuDB;
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
INSERT INTO t3 VALUES (1);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
SELECT * FROM t3 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
connection server_2;
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
SELECT * FROM t3 ORDER BY a;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
SELECT * FROM mysql.gtid_slave_pos ORDER BY sub_id;
|
||||||
|
domain_id sub_id server_id seq_no
|
||||||
|
0 3 1 3
|
||||||
|
0 4 1 4
|
||||||
|
SELECT * FROM ( SELECT * FROM mysql.gtid_slave_pos_innodb
|
||||||
|
UNION ALL SELECT * FROM mysql.gtid_slave_pos_innodb_redundant) inner_select
|
||||||
|
ORDER BY sub_id;
|
||||||
|
domain_id sub_id server_id seq_no
|
||||||
|
0 5 1 5
|
||||||
|
SELECT * FROM mysql.gtid_slave_pos_tokudb ORDER BY sub_id;
|
||||||
|
domain_id sub_id server_id seq_no
|
||||||
|
0 6 1 6
|
||||||
|
connection server_2;
|
||||||
|
FLUSH NO_WRITE_TO_BINLOG STATUS;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
INSERT INTO t1 VALUES (100);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
INSERT INTO t2 VALUES (101);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
INSERT INTO t3 VALUES (101);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t3 VALUES (102);
|
||||||
|
INSERT INTO t2 VALUES (103);
|
||||||
|
COMMIT;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 1
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES (104);
|
||||||
|
INSERT INTO t3 VALUES (105);
|
||||||
|
COMMIT;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 2
|
||||||
|
UPDATE t2, t3 SET t2.a=106, t3.a=107 WHERE t2.a=104 AND t3.a=105;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 3
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
INSERT INTO t1 VALUES (200);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 3
|
||||||
|
INSERT INTO t2 VALUES (201);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 3
|
||||||
|
INSERT INTO t3 VALUES (201);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 3
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t3 VALUES (202);
|
||||||
|
INSERT INTO t2 VALUES (203);
|
||||||
|
COMMIT;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 4
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES (204);
|
||||||
|
INSERT INTO t3 VALUES (205);
|
||||||
|
COMMIT;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 5
|
||||||
|
UPDATE t2, t3 SET t2.a=206, t3.a=207 WHERE t2.a=204 AND t3.a=205;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
Variable_name Value
|
||||||
|
Transactions_multi_engine 6
|
||||||
|
DELETE FROM t1 WHERE a >= 100;
|
||||||
|
DELETE FROM t2 WHERE a >= 100;
|
||||||
|
DELETE FROM t3 WHERE a >= 100;
|
||||||
|
connection server_2;
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_tokudb;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_myisam_redundant;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_innodb_redundant;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
FLUSH NO_WRITE_TO_BINLOG STATUS;
|
||||||
|
include/start_slave.inc
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 0
|
||||||
|
Transactions_gtid_foreign_engine 0
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t1 VALUES (100);
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 0
|
||||||
|
Transactions_gtid_foreign_engine 0
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t2 VALUES (101);
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 0
|
||||||
|
Transactions_gtid_foreign_engine 0
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t3 VALUES (101);
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 0
|
||||||
|
Transactions_gtid_foreign_engine 1
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
connection server_1;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t3 VALUES (102);
|
||||||
|
INSERT INTO t2 VALUES (103);
|
||||||
|
COMMIT;
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 1
|
||||||
|
Transactions_gtid_foreign_engine 1
|
||||||
|
Transactions_multi_engine 1
|
||||||
|
connection server_1;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES (104);
|
||||||
|
INSERT INTO t3 VALUES (105);
|
||||||
|
COMMIT;
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 2
|
||||||
|
Transactions_gtid_foreign_engine 1
|
||||||
|
Transactions_multi_engine 2
|
||||||
|
connection server_1;
|
||||||
|
UPDATE t2, t3 SET t2.a=106, t3.a=107 WHERE t2.a=104 AND t3.a=105;
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 3
|
||||||
|
Transactions_gtid_foreign_engine 1
|
||||||
|
Transactions_multi_engine 3
|
||||||
|
connection server_2;
|
||||||
|
connection server_2;
|
||||||
|
SHOW VARIABLES LIKE 'log_bin';
|
||||||
|
Variable_name Value
|
||||||
|
log_bin OFF
|
||||||
|
include/start_slave.inc
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 0
|
||||||
|
Transactions_gtid_foreign_engine 0
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t1 VALUES (200);
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 0
|
||||||
|
Transactions_gtid_foreign_engine 0
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t2 VALUES (201);
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 0
|
||||||
|
Transactions_gtid_foreign_engine 0
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
connection server_1;
|
||||||
|
INSERT INTO t3 VALUES (201);
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 0
|
||||||
|
Transactions_gtid_foreign_engine 1
|
||||||
|
Transactions_multi_engine 0
|
||||||
|
connection server_1;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t3 VALUES (202);
|
||||||
|
INSERT INTO t2 VALUES (203);
|
||||||
|
COMMIT;
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 1
|
||||||
|
Transactions_gtid_foreign_engine 1
|
||||||
|
Transactions_multi_engine 1
|
||||||
|
connection server_1;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES (204);
|
||||||
|
INSERT INTO t3 VALUES (205);
|
||||||
|
COMMIT;
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 2
|
||||||
|
Transactions_gtid_foreign_engine 1
|
||||||
|
Transactions_multi_engine 2
|
||||||
|
connection server_1;
|
||||||
|
UPDATE t2, t3 SET t2.a=206, t3.a=207 WHERE t2.a=204 AND t3.a=205;
|
||||||
|
connection server_2;
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
Variable_name Value
|
||||||
|
Rpl_transactions_multi_engine 3
|
||||||
|
Transactions_gtid_foreign_engine 1
|
||||||
|
Transactions_multi_engine 3
|
||||||
|
connection server_2;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_innodb;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
connection server_1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
DROP TABLE t3;
|
||||||
|
include/rpl_end.inc
|
232
storage/tokudb/mysql-test/tokudb_rpl/t/mdev12179.test
Normal file
232
storage/tokudb/mysql-test/tokudb_rpl/t/mdev12179.test
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
--source include/have_tokudb.inc
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
--source include/master-slave.inc
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
CHANGE MASTER TO master_use_gtid=slave_pos;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_innodb LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_innodb ENGINE=InnoDB;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_tokudb LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_tokudb ENGINE=TokuDB;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_myisam_redundant LIKE mysql.gtid_slave_pos;
|
||||||
|
CREATE TABLE mysql.gtid_slave_pos_innodb_redundant LIKE mysql.gtid_slave_pos;
|
||||||
|
ALTER TABLE mysql.gtid_slave_pos_innodb_redundant ENGINE=InnoDB;
|
||||||
|
call mtr.add_suppression("Ignoring redundant table.*since.*has the same storage engine");
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||||
|
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t3 (a INT PRIMARY KEY) ENGINE=TokuDB;
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
INSERT INTO t3 VALUES (1);
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
SELECT * FROM t3 ORDER BY a;
|
||||||
|
--save_master_pos
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
||||||
|
SELECT * FROM t3 ORDER BY a;
|
||||||
|
SELECT * FROM mysql.gtid_slave_pos ORDER BY sub_id;
|
||||||
|
SELECT * FROM ( SELECT * FROM mysql.gtid_slave_pos_innodb
|
||||||
|
UNION ALL SELECT * FROM mysql.gtid_slave_pos_innodb_redundant) inner_select
|
||||||
|
ORDER BY sub_id;
|
||||||
|
SELECT * FROM mysql.gtid_slave_pos_tokudb ORDER BY sub_id;
|
||||||
|
|
||||||
|
|
||||||
|
# Test status variable Transactions_multi_engine.
|
||||||
|
--connection server_2
|
||||||
|
FLUSH NO_WRITE_TO_BINLOG STATUS;
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
INSERT INTO t1 VALUES (100);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
INSERT INTO t2 VALUES (101);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
INSERT INTO t3 VALUES (101);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t3 VALUES (102);
|
||||||
|
INSERT INTO t2 VALUES (103);
|
||||||
|
COMMIT;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES (104);
|
||||||
|
INSERT INTO t3 VALUES (105);
|
||||||
|
COMMIT;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
UPDATE t2, t3 SET t2.a=106, t3.a=107 WHERE t2.a=104 AND t3.a=105;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
# Try again with binlog enabled.
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
INSERT INTO t1 VALUES (200);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
INSERT INTO t2 VALUES (201);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
INSERT INTO t3 VALUES (201);
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t3 VALUES (202);
|
||||||
|
INSERT INTO t2 VALUES (203);
|
||||||
|
COMMIT;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES (204);
|
||||||
|
INSERT INTO t3 VALUES (205);
|
||||||
|
COMMIT;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
UPDATE t2, t3 SET t2.a=206, t3.a=207 WHERE t2.a=204 AND t3.a=205;
|
||||||
|
SHOW STATUS LIKE "Transactions_multi_engine";
|
||||||
|
|
||||||
|
DELETE FROM t1 WHERE a >= 100;
|
||||||
|
DELETE FROM t2 WHERE a >= 100;
|
||||||
|
DELETE FROM t3 WHERE a >= 100;
|
||||||
|
|
||||||
|
|
||||||
|
# Test status variables Rpl_transactions_multi_engine and Transactions_gtid_foreign_engine.
|
||||||
|
# Have mysql.gtid_slave_pos* for myisam and innodb but not tokudb.
|
||||||
|
--connection server_2
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_tokudb;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_myisam_redundant;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_innodb_redundant;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
FLUSH NO_WRITE_TO_BINLOG STATUS;
|
||||||
|
--source include/start_slave.inc
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t1 VALUES (100);
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t2 VALUES (101);
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t3 VALUES (101);
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t3 VALUES (102);
|
||||||
|
INSERT INTO t2 VALUES (103);
|
||||||
|
COMMIT;
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES (104);
|
||||||
|
INSERT INTO t3 VALUES (105);
|
||||||
|
COMMIT;
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
UPDATE t2, t3 SET t2.a=106, t3.a=107 WHERE t2.a=104 AND t3.a=105;
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
# Now the same thing, but without binlogging on the slave.
|
||||||
|
--connection server_2
|
||||||
|
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
wait
|
||||||
|
EOF
|
||||||
|
--shutdown_server 30
|
||||||
|
--source include/wait_until_disconnected.inc
|
||||||
|
|
||||||
|
# Restart without binary log.
|
||||||
|
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
|
||||||
|
restart: --skip-log-bin
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
--enable_reconnect
|
||||||
|
--source include/wait_until_connected_again.inc
|
||||||
|
SHOW VARIABLES LIKE 'log_bin';
|
||||||
|
--source include/start_slave.inc
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t1 VALUES (200);
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t2 VALUES (201);
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
INSERT INTO t3 VALUES (201);
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t3 VALUES (202);
|
||||||
|
INSERT INTO t2 VALUES (203);
|
||||||
|
COMMIT;
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES (204);
|
||||||
|
INSERT INTO t3 VALUES (205);
|
||||||
|
COMMIT;
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
UPDATE t2, t3 SET t2.a=206, t3.a=207 WHERE t2.a=204 AND t3.a=205;
|
||||||
|
--save_master_pos
|
||||||
|
--connection server_2
|
||||||
|
--sync_with_master
|
||||||
|
SHOW STATUS LIKE "%transactions%engine";
|
||||||
|
|
||||||
|
|
||||||
|
--connection server_2
|
||||||
|
SET sql_log_bin=0;
|
||||||
|
DROP TABLE mysql.gtid_slave_pos_innodb;
|
||||||
|
SET sql_log_bin=1;
|
||||||
|
|
||||||
|
--connection server_1
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
DROP TABLE t3;
|
||||||
|
|
||||||
|
--source include/rpl_end.inc
|
Loading…
x
Reference in New Issue
Block a user