mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-162 Enhanced semisync replication
Implement --semi-sync-master-wait-point=AFTER_SYNC|AFTER_COMMIT. When AFTER_SYNC, the semi-sync wait will be done earlier, before the storage engine commit rather than after. This means that a transaction will not be visible on the master until at least one slave has received it.
This commit is contained in:
committed by
Kristian Nielsen
parent
4d8b346e07
commit
0b87de124d
@ -3,11 +3,11 @@ SELECT variable_value INTO @commits FROM information_schema.global_status
|
||||
WHERE variable_name = 'binlog_commits';
|
||||
SELECT variable_value INTO @group_commits FROM information_schema.global_status
|
||||
WHERE variable_name = 'binlog_group_commits';
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group1_running WAIT_FOR group2_queued";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group1_running WAIT_FOR group2_queued";
|
||||
INSERT INTO t1 VALUES ("con1");
|
||||
set DEBUG_SYNC= "now WAIT_FOR group1_running";
|
||||
SET DEBUG_SYNC= "commit_after_prepare_ordered SIGNAL group2_con2";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group2_running";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group2_running";
|
||||
SET DEBUG_SYNC= "commit_after_release_LOCK_log WAIT_FOR group3_committed";
|
||||
SET DEBUG_SYNC= "commit_after_group_run_commit_ordered SIGNAL group2_visible WAIT_FOR group2_checked";
|
||||
INSERT INTO t1 VALUES ("con2");
|
||||
@ -25,7 +25,7 @@ SET DEBUG_SYNC= "now SIGNAL group2_queued";
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
con1
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group3_con5";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group3_con5";
|
||||
SET DEBUG_SYNC= "commit_after_get_LOCK_log SIGNAL con5_leader WAIT_FOR con6_queued";
|
||||
set DEBUG_SYNC= "now WAIT_FOR group2_running";
|
||||
INSERT INTO t1 VALUES ("con5");
|
||||
|
@ -3,11 +3,11 @@ SELECT variable_value INTO @commits FROM information_schema.global_status
|
||||
WHERE variable_name = 'binlog_commits';
|
||||
SELECT variable_value INTO @group_commits FROM information_schema.global_status
|
||||
WHERE variable_name = 'binlog_group_commits';
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group1_running WAIT_FOR group2_queued";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group1_running WAIT_FOR group2_queued";
|
||||
INSERT INTO t1 VALUES ("con1");
|
||||
set DEBUG_SYNC= "now WAIT_FOR group1_running";
|
||||
SET DEBUG_SYNC= "commit_after_prepare_ordered SIGNAL group2_con2";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group2_running";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group2_running";
|
||||
SET DEBUG_SYNC= "commit_after_release_LOCK_log WAIT_FOR group3_committed";
|
||||
INSERT INTO t1 VALUES ("con2");
|
||||
SET DEBUG_SYNC= "now WAIT_FOR group2_con2";
|
||||
@ -25,7 +25,7 @@ SET DEBUG_SYNC= "now SIGNAL group2_queued";
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
con1
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group3_con5";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group3_con5";
|
||||
SET DEBUG_SYNC= "commit_after_get_LOCK_log SIGNAL con5_leader WAIT_FOR con6_queued";
|
||||
set DEBUG_SYNC= "now WAIT_FOR group2_running";
|
||||
INSERT INTO t1 VALUES ("con5");
|
||||
|
@ -27,7 +27,7 @@ connect(con6,localhost,root,,);
|
||||
# group2 to queue up before finishing.
|
||||
|
||||
connection con1;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group1_running WAIT_FOR group2_queued";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group1_running WAIT_FOR group2_queued";
|
||||
send INSERT INTO t1 VALUES ("con1");
|
||||
|
||||
# Make group2 (with three threads) queue up.
|
||||
@ -37,7 +37,7 @@ send INSERT INTO t1 VALUES ("con1");
|
||||
connection con2;
|
||||
set DEBUG_SYNC= "now WAIT_FOR group1_running";
|
||||
SET DEBUG_SYNC= "commit_after_prepare_ordered SIGNAL group2_con2";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group2_running";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group2_running";
|
||||
SET DEBUG_SYNC= "commit_after_release_LOCK_log WAIT_FOR group3_committed";
|
||||
SET DEBUG_SYNC= "commit_after_group_run_commit_ordered SIGNAL group2_visible WAIT_FOR group2_checked";
|
||||
send INSERT INTO t1 VALUES ("con2");
|
||||
@ -69,7 +69,7 @@ connection default;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
connection con5;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group3_con5";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group3_con5";
|
||||
SET DEBUG_SYNC= "commit_after_get_LOCK_log SIGNAL con5_leader WAIT_FOR con6_queued";
|
||||
set DEBUG_SYNC= "now WAIT_FOR group2_running";
|
||||
send INSERT INTO t1 VALUES ("con5");
|
||||
|
@ -27,7 +27,7 @@ connect(con6,localhost,root,,);
|
||||
# group2 to queue up before finishing.
|
||||
|
||||
connection con1;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group1_running WAIT_FOR group2_queued";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group1_running WAIT_FOR group2_queued";
|
||||
send INSERT INTO t1 VALUES ("con1");
|
||||
|
||||
# Make group2 (with three threads) queue up.
|
||||
@ -37,7 +37,7 @@ send INSERT INTO t1 VALUES ("con1");
|
||||
connection con2;
|
||||
set DEBUG_SYNC= "now WAIT_FOR group1_running";
|
||||
SET DEBUG_SYNC= "commit_after_prepare_ordered SIGNAL group2_con2";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group2_running";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group2_running";
|
||||
SET DEBUG_SYNC= "commit_after_release_LOCK_log WAIT_FOR group3_committed";
|
||||
send INSERT INTO t1 VALUES ("con2");
|
||||
connection con3;
|
||||
@ -69,7 +69,7 @@ connection default;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
|
||||
connection con5;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL group3_con5";
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group3_con5";
|
||||
SET DEBUG_SYNC= "commit_after_get_LOCK_log SIGNAL con5_leader WAIT_FOR con6_queued";
|
||||
set DEBUG_SYNC= "now WAIT_FOR group2_running";
|
||||
send INSERT INTO t1 VALUES ("con5");
|
||||
|
@ -11,9 +11,9 @@ wait/synch/mutex/sql/gtid_waiting::LOCK_gtid_waiting YES YES
|
||||
wait/synch/mutex/sql/hash_filo::lock YES YES
|
||||
wait/synch/mutex/sql/HA_DATA_PARTITION::LOCK_auto_inc YES YES
|
||||
wait/synch/mutex/sql/LOCK_active_mi YES YES
|
||||
wait/synch/mutex/sql/LOCK_after_binlog_sync YES YES
|
||||
wait/synch/mutex/sql/LOCK_audit_mask YES YES
|
||||
wait/synch/mutex/sql/LOCK_binlog_state YES YES
|
||||
wait/synch/mutex/sql/LOCK_commit_ordered YES YES
|
||||
select * from performance_schema.setup_instruments
|
||||
where name like 'Wait/Synch/Rwlock/sql/%'
|
||||
and name not in ('wait/synch/rwlock/sql/CRYPTO_dynlock_value::lock')
|
||||
|
467
mysql-test/suite/rpl/r/rpl_semi_sync_after_sync.result
Normal file
467
mysql-test/suite/rpl/r/rpl_semi_sync_after_sync.result
Normal file
@ -0,0 +1,467 @@
|
||||
set global rpl_semi_sync_master_wait_point=AFTER_SYNC;
|
||||
include/master-slave.inc
|
||||
[connection master]
|
||||
call mtr.add_suppression("Timeout waiting for reply of binlog");
|
||||
call mtr.add_suppression("Read semi-sync reply");
|
||||
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.");
|
||||
call mtr.add_suppression("Master server does not support semi-sync");
|
||||
call mtr.add_suppression("Semi-sync slave .* reply");
|
||||
call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group");
|
||||
#
|
||||
# Uninstall semi-sync plugins on master and slave
|
||||
#
|
||||
include/stop_slave.inc
|
||||
reset slave;
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
set global rpl_semi_sync_slave_enabled= 0;
|
||||
reset master;
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
set global rpl_semi_sync_slave_enabled= 0;
|
||||
#
|
||||
# Main test of semi-sync replication start here
|
||||
#
|
||||
[ on master ]
|
||||
set global rpl_semi_sync_master_timeout= 60000;
|
||||
[ default state of semi-sync on master should be OFF ]
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled OFF
|
||||
[ enable semi-sync on master ]
|
||||
set global rpl_semi_sync_master_enabled = 1;
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled ON
|
||||
[ status of semi-sync on master should be ON even without any semi-sync slaves ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 0
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
#
|
||||
# BUG#45672 Semisync repl: ActiveTranx:insert_tranx_node: transaction node allocation failed
|
||||
# BUG#45673 Semisynch reports correct operation even if no slave is connected
|
||||
#
|
||||
[ status of semi-sync on master should be OFF ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 0
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
reset master;
|
||||
[ on slave ]
|
||||
[ default state of semi-sync on slave should be OFF ]
|
||||
show variables like 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled OFF
|
||||
[ enable semi-sync on slave ]
|
||||
set global rpl_semi_sync_slave_enabled = 1;
|
||||
show variables like 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled ON
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
[ initial master state after the semi-sync slave connected ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
create table t1(a int) engine = ENGINE_TYPE;
|
||||
[ master state after CREATE TABLE statement ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 1
|
||||
select CONNECTIONS_NORMAL_SLAVE - CONNECTIONS_NORMAL_SLAVE as 'Should be 0';
|
||||
Should be 0
|
||||
0
|
||||
[ insert records to table ]
|
||||
insert t1 values (10);
|
||||
insert t1 values (9);
|
||||
insert t1 values (8);
|
||||
insert t1 values (7);
|
||||
insert t1 values (6);
|
||||
insert t1 values (5);
|
||||
insert t1 values (4);
|
||||
insert t1 values (3);
|
||||
insert t1 values (2);
|
||||
insert t1 values (1);
|
||||
[ master status after inserts ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 11
|
||||
[ on slave ]
|
||||
[ slave status after replicated inserts ]
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status ON
|
||||
select count(distinct a) from t1;
|
||||
count(distinct a)
|
||||
10
|
||||
select min(a) from t1;
|
||||
min(a)
|
||||
1
|
||||
select max(a) from t1;
|
||||
max(a)
|
||||
10
|
||||
|
||||
# BUG#50157
|
||||
# semi-sync replication crashes when replicating a transaction which
|
||||
# include 'CREATE TEMPORARY TABLE `MyISAM_t` SELECT * FROM `Innodb_t` ;
|
||||
[ on master ]
|
||||
SET SESSION AUTOCOMMIT= 0;
|
||||
CREATE TABLE t2(c1 INT) ENGINE=innodb;
|
||||
BEGIN;
|
||||
|
||||
# Even though it is in a transaction, this statement is binlogged into binlog
|
||||
# file immediately.
|
||||
CREATE TEMPORARY TABLE t3 SELECT c1 FROM t2 where 1=1;
|
||||
|
||||
# These statements will not be binlogged until the transaction is committed
|
||||
INSERT INTO t2 VALUES(11);
|
||||
INSERT INTO t2 VALUES(22);
|
||||
COMMIT;
|
||||
DROP TABLE t2, t3;
|
||||
SET SESSION AUTOCOMMIT= 1;
|
||||
#
|
||||
# Test semi-sync master will switch OFF after one transaction
|
||||
# timeout waiting for slave reply.
|
||||
#
|
||||
include/stop_slave.inc
|
||||
[ on master ]
|
||||
set global rpl_semi_sync_master_timeout= 5000;
|
||||
[ master status should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 16
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
[ semi-sync replication of these transactions will fail ]
|
||||
insert into t1 values (500);
|
||||
[ master status should be OFF ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 1
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 16
|
||||
delete from t1 where a=10;
|
||||
delete from t1 where a=9;
|
||||
delete from t1 where a=8;
|
||||
delete from t1 where a=7;
|
||||
delete from t1 where a=6;
|
||||
delete from t1 where a=5;
|
||||
delete from t1 where a=4;
|
||||
delete from t1 where a=3;
|
||||
delete from t1 where a=2;
|
||||
delete from t1 where a=1;
|
||||
insert into t1 values (100);
|
||||
[ master status should be OFF ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 12
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 16
|
||||
#
|
||||
# Test semi-sync status on master will be ON again when slave catches up
|
||||
#
|
||||
[ on slave ]
|
||||
[ slave status should be OFF ]
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
include/start_slave.inc
|
||||
[ slave status should be ON ]
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status ON
|
||||
select count(distinct a) from t1;
|
||||
count(distinct a)
|
||||
2
|
||||
select min(a) from t1;
|
||||
min(a)
|
||||
100
|
||||
select max(a) from t1;
|
||||
max(a)
|
||||
500
|
||||
[ on master ]
|
||||
[ master status should be ON again after slave catches up ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 12
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 16
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
#
|
||||
# Test disable/enable master semi-sync on the fly.
|
||||
#
|
||||
drop table t1;
|
||||
[ on slave ]
|
||||
include/stop_slave.inc
|
||||
#
|
||||
# Flush status
|
||||
#
|
||||
[ Semi-sync master status variables before FLUSH STATUS ]
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 12
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 17
|
||||
FLUSH NO_WRITE_TO_BINLOG STATUS;
|
||||
[ Semi-sync master status variables after FLUSH STATUS ]
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
[ on master ]
|
||||
show master logs;
|
||||
Log_name master-bin.000001
|
||||
File_size #
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled ON
|
||||
[ disable semi-sync on the fly ]
|
||||
set global rpl_semi_sync_master_enabled=0;
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled OFF
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
[ enable semi-sync on the fly ]
|
||||
set global rpl_semi_sync_master_enabled=1;
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled ON
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
#
|
||||
# Test RESET MASTER/SLAVE
|
||||
#
|
||||
[ on slave ]
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
create table t1 (a int) engine = ENGINE_TYPE;
|
||||
drop table t1;
|
||||
show status like 'Rpl_relay%';
|
||||
Variable_name Value
|
||||
[ test reset master ]
|
||||
[ on master]
|
||||
reset master;
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
[ on slave ]
|
||||
include/stop_slave.inc
|
||||
reset slave;
|
||||
kill query _tid;
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
create table t1 (a int) engine = ENGINE_TYPE;
|
||||
insert into t1 values (1);
|
||||
insert into t1 values (2), (3);
|
||||
[ on slave ]
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
[ on master ]
|
||||
[ master semi-sync status should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 3
|
||||
#
|
||||
# Start semi-sync replication without SUPER privilege
|
||||
#
|
||||
include/stop_slave.inc
|
||||
reset slave;
|
||||
[ on master ]
|
||||
reset master;
|
||||
kill query _tid;
|
||||
set sql_log_bin=0;
|
||||
grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl_password';
|
||||
flush privileges;
|
||||
set sql_log_bin=1;
|
||||
[ on slave ]
|
||||
grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl_password';
|
||||
flush privileges;
|
||||
change master to master_user='rpl',master_password='rpl_password';
|
||||
include/start_slave.inc
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status ON
|
||||
[ on master ]
|
||||
[ master semi-sync should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
insert into t1 values (4);
|
||||
insert into t1 values (5);
|
||||
[ master semi-sync should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 2
|
||||
#
|
||||
# Test semi-sync slave connect to non-semi-sync master
|
||||
#
|
||||
[ on slave ]
|
||||
include/stop_slave.inc
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
[ on master ]
|
||||
kill query _tid;
|
||||
[ Semi-sync status on master should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 0
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
[ on slave ]
|
||||
SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled ON
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
insert into t1 values (8);
|
||||
[ master semi-sync clients should be 1, status should be OFF ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
[ on slave ]
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status ON
|
||||
include/stop_slave.inc
|
||||
[ on master ]
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
[ on slave ]
|
||||
SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled ON
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
insert into t1 values (10);
|
||||
#
|
||||
# Test non-semi-sync slave connect to semi-sync master
|
||||
#
|
||||
set global rpl_semi_sync_master_timeout= 5000;
|
||||
set global rpl_semi_sync_master_enabled= 1;
|
||||
[ on slave ]
|
||||
include/stop_slave.inc
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
[ uninstall semi-sync slave plugin ]
|
||||
set global rpl_semi_sync_slave_enabled= 0;
|
||||
[ reinstall semi-sync slave plugin and disable semi-sync ]
|
||||
SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled OFF
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
include/start_slave.inc
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
include/stop_slave.inc
|
||||
set global rpl_semi_sync_slave_enabled= 0;
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
change master to master_user='root',master_password='';
|
||||
include/start_slave.inc
|
||||
drop table t1;
|
||||
drop user rpl@127.0.0.1;
|
||||
flush privileges;
|
||||
set global rpl_semi_sync_master_timeout= default;
|
||||
include/rpl_end.inc
|
||||
set global rpl_semi_sync_master_wait_point=default;
|
467
mysql-test/suite/rpl/r/rpl_semi_sync_after_sync_row.result
Normal file
467
mysql-test/suite/rpl/r/rpl_semi_sync_after_sync_row.result
Normal file
@ -0,0 +1,467 @@
|
||||
set global rpl_semi_sync_master_wait_point=AFTER_SYNC;
|
||||
include/master-slave.inc
|
||||
[connection master]
|
||||
call mtr.add_suppression("Timeout waiting for reply of binlog");
|
||||
call mtr.add_suppression("Read semi-sync reply");
|
||||
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.");
|
||||
call mtr.add_suppression("Master server does not support semi-sync");
|
||||
call mtr.add_suppression("Semi-sync slave .* reply");
|
||||
call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group");
|
||||
#
|
||||
# Uninstall semi-sync plugins on master and slave
|
||||
#
|
||||
include/stop_slave.inc
|
||||
reset slave;
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
set global rpl_semi_sync_slave_enabled= 0;
|
||||
reset master;
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
set global rpl_semi_sync_slave_enabled= 0;
|
||||
#
|
||||
# Main test of semi-sync replication start here
|
||||
#
|
||||
[ on master ]
|
||||
set global rpl_semi_sync_master_timeout= 60000;
|
||||
[ default state of semi-sync on master should be OFF ]
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled OFF
|
||||
[ enable semi-sync on master ]
|
||||
set global rpl_semi_sync_master_enabled = 1;
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled ON
|
||||
[ status of semi-sync on master should be ON even without any semi-sync slaves ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 0
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
#
|
||||
# BUG#45672 Semisync repl: ActiveTranx:insert_tranx_node: transaction node allocation failed
|
||||
# BUG#45673 Semisynch reports correct operation even if no slave is connected
|
||||
#
|
||||
[ status of semi-sync on master should be OFF ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 0
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
reset master;
|
||||
[ on slave ]
|
||||
[ default state of semi-sync on slave should be OFF ]
|
||||
show variables like 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled OFF
|
||||
[ enable semi-sync on slave ]
|
||||
set global rpl_semi_sync_slave_enabled = 1;
|
||||
show variables like 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled ON
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
[ initial master state after the semi-sync slave connected ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
create table t1(a int) engine = ENGINE_TYPE;
|
||||
[ master state after CREATE TABLE statement ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 1
|
||||
select CONNECTIONS_NORMAL_SLAVE - CONNECTIONS_NORMAL_SLAVE as 'Should be 0';
|
||||
Should be 0
|
||||
0
|
||||
[ insert records to table ]
|
||||
insert t1 values (10);
|
||||
insert t1 values (9);
|
||||
insert t1 values (8);
|
||||
insert t1 values (7);
|
||||
insert t1 values (6);
|
||||
insert t1 values (5);
|
||||
insert t1 values (4);
|
||||
insert t1 values (3);
|
||||
insert t1 values (2);
|
||||
insert t1 values (1);
|
||||
[ master status after inserts ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 11
|
||||
[ on slave ]
|
||||
[ slave status after replicated inserts ]
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status ON
|
||||
select count(distinct a) from t1;
|
||||
count(distinct a)
|
||||
10
|
||||
select min(a) from t1;
|
||||
min(a)
|
||||
1
|
||||
select max(a) from t1;
|
||||
max(a)
|
||||
10
|
||||
|
||||
# BUG#50157
|
||||
# semi-sync replication crashes when replicating a transaction which
|
||||
# include 'CREATE TEMPORARY TABLE `MyISAM_t` SELECT * FROM `Innodb_t` ;
|
||||
[ on master ]
|
||||
SET SESSION AUTOCOMMIT= 0;
|
||||
CREATE TABLE t2(c1 INT) ENGINE=innodb;
|
||||
BEGIN;
|
||||
|
||||
# Even though it is in a transaction, this statement is binlogged into binlog
|
||||
# file immediately.
|
||||
CREATE TEMPORARY TABLE t3 SELECT c1 FROM t2 where 1=1;
|
||||
|
||||
# These statements will not be binlogged until the transaction is committed
|
||||
INSERT INTO t2 VALUES(11);
|
||||
INSERT INTO t2 VALUES(22);
|
||||
COMMIT;
|
||||
DROP TABLE t2, t3;
|
||||
SET SESSION AUTOCOMMIT= 1;
|
||||
#
|
||||
# Test semi-sync master will switch OFF after one transaction
|
||||
# timeout waiting for slave reply.
|
||||
#
|
||||
include/stop_slave.inc
|
||||
[ on master ]
|
||||
set global rpl_semi_sync_master_timeout= 5000;
|
||||
[ master status should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 15
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
[ semi-sync replication of these transactions will fail ]
|
||||
insert into t1 values (500);
|
||||
[ master status should be OFF ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 1
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 15
|
||||
delete from t1 where a=10;
|
||||
delete from t1 where a=9;
|
||||
delete from t1 where a=8;
|
||||
delete from t1 where a=7;
|
||||
delete from t1 where a=6;
|
||||
delete from t1 where a=5;
|
||||
delete from t1 where a=4;
|
||||
delete from t1 where a=3;
|
||||
delete from t1 where a=2;
|
||||
delete from t1 where a=1;
|
||||
insert into t1 values (100);
|
||||
[ master status should be OFF ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 12
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 15
|
||||
#
|
||||
# Test semi-sync status on master will be ON again when slave catches up
|
||||
#
|
||||
[ on slave ]
|
||||
[ slave status should be OFF ]
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
include/start_slave.inc
|
||||
[ slave status should be ON ]
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status ON
|
||||
select count(distinct a) from t1;
|
||||
count(distinct a)
|
||||
2
|
||||
select min(a) from t1;
|
||||
min(a)
|
||||
100
|
||||
select max(a) from t1;
|
||||
max(a)
|
||||
500
|
||||
[ on master ]
|
||||
[ master status should be ON again after slave catches up ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 12
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 15
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
#
|
||||
# Test disable/enable master semi-sync on the fly.
|
||||
#
|
||||
drop table t1;
|
||||
[ on slave ]
|
||||
include/stop_slave.inc
|
||||
#
|
||||
# Flush status
|
||||
#
|
||||
[ Semi-sync master status variables before FLUSH STATUS ]
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 12
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 16
|
||||
FLUSH NO_WRITE_TO_BINLOG STATUS;
|
||||
[ Semi-sync master status variables after FLUSH STATUS ]
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
[ on master ]
|
||||
show master logs;
|
||||
Log_name master-bin.000001
|
||||
File_size #
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled ON
|
||||
[ disable semi-sync on the fly ]
|
||||
set global rpl_semi_sync_master_enabled=0;
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled OFF
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
[ enable semi-sync on the fly ]
|
||||
set global rpl_semi_sync_master_enabled=1;
|
||||
show variables like 'rpl_semi_sync_master_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_enabled ON
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
#
|
||||
# Test RESET MASTER/SLAVE
|
||||
#
|
||||
[ on slave ]
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
create table t1 (a int) engine = ENGINE_TYPE;
|
||||
drop table t1;
|
||||
show status like 'Rpl_relay%';
|
||||
Variable_name Value
|
||||
[ test reset master ]
|
||||
[ on master]
|
||||
reset master;
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
[ on slave ]
|
||||
include/stop_slave.inc
|
||||
reset slave;
|
||||
kill query _tid;
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
create table t1 (a int) engine = ENGINE_TYPE;
|
||||
insert into t1 values (1);
|
||||
insert into t1 values (2), (3);
|
||||
[ on slave ]
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
[ on master ]
|
||||
[ master semi-sync status should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 3
|
||||
#
|
||||
# Start semi-sync replication without SUPER privilege
|
||||
#
|
||||
include/stop_slave.inc
|
||||
reset slave;
|
||||
[ on master ]
|
||||
reset master;
|
||||
kill query _tid;
|
||||
set sql_log_bin=0;
|
||||
grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl_password';
|
||||
flush privileges;
|
||||
set sql_log_bin=1;
|
||||
[ on slave ]
|
||||
grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl_password';
|
||||
flush privileges;
|
||||
change master to master_user='rpl',master_password='rpl_password';
|
||||
include/start_slave.inc
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status ON
|
||||
[ on master ]
|
||||
[ master semi-sync should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 0
|
||||
insert into t1 values (4);
|
||||
insert into t1 values (5);
|
||||
[ master semi-sync should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_no_tx 0
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_yes_tx 2
|
||||
#
|
||||
# Test semi-sync slave connect to non-semi-sync master
|
||||
#
|
||||
[ on slave ]
|
||||
include/stop_slave.inc
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
[ on master ]
|
||||
kill query _tid;
|
||||
[ Semi-sync status on master should be ON ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 0
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status ON
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
[ on slave ]
|
||||
SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled ON
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
insert into t1 values (8);
|
||||
[ master semi-sync clients should be 1, status should be OFF ]
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_status OFF
|
||||
[ on slave ]
|
||||
show status like 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status ON
|
||||
include/stop_slave.inc
|
||||
[ on master ]
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
[ on slave ]
|
||||
SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled ON
|
||||
include/start_slave.inc
|
||||
[ on master ]
|
||||
insert into t1 values (10);
|
||||
#
|
||||
# Test non-semi-sync slave connect to semi-sync master
|
||||
#
|
||||
set global rpl_semi_sync_master_timeout= 5000;
|
||||
set global rpl_semi_sync_master_enabled= 1;
|
||||
[ on slave ]
|
||||
include/stop_slave.inc
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
[ uninstall semi-sync slave plugin ]
|
||||
set global rpl_semi_sync_slave_enabled= 0;
|
||||
[ reinstall semi-sync slave plugin and disable semi-sync ]
|
||||
SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_slave_enabled OFF
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
include/start_slave.inc
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_slave_status OFF
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
include/stop_slave.inc
|
||||
set global rpl_semi_sync_slave_enabled= 0;
|
||||
set global rpl_semi_sync_master_enabled= 0;
|
||||
change master to master_user='root',master_password='';
|
||||
include/start_slave.inc
|
||||
drop table t1;
|
||||
drop user rpl@127.0.0.1;
|
||||
flush privileges;
|
||||
set global rpl_semi_sync_master_timeout= default;
|
||||
include/rpl_end.inc
|
||||
set global rpl_semi_sync_master_wait_point=default;
|
54
mysql-test/suite/rpl/r/rpl_semi_sync_event_after_sync.result
Normal file
54
mysql-test/suite/rpl/r/rpl_semi_sync_event_after_sync.result
Normal file
@ -0,0 +1,54 @@
|
||||
set global rpl_semi_sync_master_wait_point=AFTER_SYNC;
|
||||
include/master-slave.inc
|
||||
[connection master]
|
||||
call mtr.add_suppression("Timeout waiting for reply of binlog");
|
||||
call mtr.add_suppression("Semi-sync master .* waiting for slave reply");
|
||||
call mtr.add_suppression("Read semi-sync reply");
|
||||
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.");
|
||||
call mtr.add_suppression("Master server does not support semi-sync");
|
||||
call mtr.add_suppression("Semi-sync slave .* reply");
|
||||
call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group");
|
||||
set global rpl_semi_sync_master_enabled = 1;
|
||||
include/stop_slave.inc
|
||||
set global rpl_semi_sync_slave_enabled = 1;
|
||||
include/start_slave.inc
|
||||
SET GLOBAL event_scheduler = ON;
|
||||
CREATE TABLE t1 (i INT NOT NULL AUTO_INCREMENT PRIMARY KEY, f varchar(8)) ENGINE=ENGINE_TYPE;
|
||||
INSERT INTO t1 (f) VALUES ('a'),('a'),('a'),('a'),('a');
|
||||
INSERT INTO t1 SELECT i+5, f FROM t1;
|
||||
INSERT INTO t1 SELECT i+10, f FROM t1;
|
||||
CREATE EVENT ev1 ON SCHEDULE EVERY 1 SECOND
|
||||
DO INSERT INTO t1 VALUES (SLEEP(5),CONCAT('ev1_',CONNECTION_ID()));
|
||||
CREATE EVENT ev2 ON SCHEDULE EVERY 1 SECOND
|
||||
DO INSERT INTO t1 VALUES (SLEEP(5),CONCAT('ev2_',CONNECTION_ID()));
|
||||
STOP SLAVE IO_THREAD;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 20;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 19;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 18;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 17;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 16;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 15;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 14;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 13;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 12;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 11;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 10;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 9;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 8;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 7;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 6;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 5;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 4;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 3;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 2;
|
||||
UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = 1;
|
||||
SET GLOBAL event_scheduler = OFF;
|
||||
include/stop_slave.inc
|
||||
set global rpl_semi_sync_slave_enabled = 0;
|
||||
set global rpl_semi_sync_master_enabled = 0;
|
||||
include/start_slave.inc
|
||||
DROP EVENT ev1;
|
||||
DROP EVENT ev2;
|
||||
DROP TABLE t1;
|
||||
include/rpl_end.inc
|
||||
set global rpl_semi_sync_master_wait_point=default;
|
133
mysql-test/suite/rpl/r/rpl_semi_sync_wait_point.result
Normal file
133
mysql-test/suite/rpl/r/rpl_semi_sync_wait_point.result
Normal file
@ -0,0 +1,133 @@
|
||||
#
|
||||
# Preparation
|
||||
#
|
||||
CREATE TABLE t1 (i INT NOT NULL, PRIMARY KEY (i)) ENGINE=InnoDB;
|
||||
RESET MASTER;
|
||||
SET @@global.rpl_semi_sync_master_timeout = 60000;
|
||||
SET @@global.rpl_semi_sync_master_wait_no_slave = 1;
|
||||
# It's okay to see "Killed" but we should not see "Timeout" in the log.
|
||||
call mtr.add_suppression("Killed waiting for reply of binlog");
|
||||
call mtr.add_suppression("Run function 'after_commit' in plugin 'rpl_semi_sync_master' failed");
|
||||
call mtr.add_suppression("Run function 'after_sync' in plugin 'rpl_semi_sync_master' failed");
|
||||
#
|
||||
# Test wait point = AFTER_COMMIT
|
||||
#
|
||||
SET @@global.rpl_semi_sync_master_wait_point = AFTER_COMMIT;
|
||||
# Make another connection to INSERT from.
|
||||
SET GLOBAL rpl_semi_sync_master_enabled = 1;
|
||||
# Go ahead and send the INSERT; it should block.
|
||||
INSERT INTO t1 (i) VALUES (1);
|
||||
# The INSERT thread should now be waiting.
|
||||
SELECT state AS should_be_waiting
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
should_be_waiting
|
||||
Waiting for semi-sync ACK from slave
|
||||
# The insert should be visible to other threads
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
i
|
||||
1
|
||||
# Kill the waiting thread; it should die immediately.
|
||||
KILL @other_connection_id;
|
||||
# Collect the error from the INSERT thread; it should be disconnected.
|
||||
Got one of the listed errors
|
||||
# Wait for INSERT thread to actually disappear (KILL closes connection
|
||||
# before thread actually finishes its processing).
|
||||
# The INSERT thread should now be gone.
|
||||
SELECT state AS should_be_empty_set
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
should_be_empty_set
|
||||
# The insert is still there
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
i
|
||||
1
|
||||
# Make another connection to INSERT from.
|
||||
# Go ahead and send the INSERT; it should block.
|
||||
INSERT INTO t1 (i) VALUES (2);
|
||||
# The INSERT thread should now be waiting.
|
||||
SELECT state AS should_be_waiting
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
should_be_waiting
|
||||
Waiting for semi-sync ACK from slave
|
||||
# The insert should be visible to other threads
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
i
|
||||
1
|
||||
2
|
||||
# Now restart server
|
||||
# Done restarting server
|
||||
# Reset setting that were lost in restart
|
||||
SET @@global.rpl_semi_sync_master_timeout = 60000;
|
||||
SET @@global.rpl_semi_sync_master_wait_no_slave = 1;
|
||||
# Check that row is still there
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
i
|
||||
1
|
||||
2
|
||||
#
|
||||
# Test wait point = AFTER_SYNC
|
||||
#
|
||||
SET @@global.rpl_semi_sync_master_wait_point = AFTER_SYNC;
|
||||
# Make another connection to INSERT from.
|
||||
SET GLOBAL rpl_semi_sync_master_enabled = 1;
|
||||
# Go ahead and send the INSERT; it should block.
|
||||
INSERT INTO t1 (i) VALUES (3);
|
||||
# The INSERT thread should now be waiting.
|
||||
SELECT state AS should_be_waiting
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
should_be_waiting
|
||||
Waiting for semi-sync ACK from slave
|
||||
# The insert should NOT be visible to other threads
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
i
|
||||
1
|
||||
2
|
||||
# Kill the waiting thread; it should die immediately.
|
||||
KILL @other_connection_id;
|
||||
# Collect the error from the INSERT thread; it should be disconnected.
|
||||
Got one of the listed errors
|
||||
# Wait for INSERT thread to actually disappear (KILL closes connection
|
||||
# before thread actually finishes its processing).
|
||||
# The INSERT thread should now be gone.
|
||||
SELECT state AS should_be_empty_set
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
should_be_empty_set
|
||||
# The row inserted is there
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
i
|
||||
1
|
||||
2
|
||||
3
|
||||
# Make another connection to INSERT from.
|
||||
# Go ahead and send the INSERT; it should block.
|
||||
INSERT INTO t1 (i) VALUES (4);
|
||||
# The INSERT thread should now be waiting.
|
||||
SELECT state AS should_be_waiting
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
should_be_waiting
|
||||
Waiting for semi-sync ACK from slave
|
||||
# The insert should NOT be visible to other threads
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
i
|
||||
1
|
||||
2
|
||||
3
|
||||
# Now restart server
|
||||
# Done restarting server
|
||||
# Reset setting that were lost in restart
|
||||
SET @@global.rpl_semi_sync_master_timeout = 60000;
|
||||
SET @@global.rpl_semi_sync_master_wait_no_slave = 1;
|
||||
# But the row inserted is there
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
i
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
#
|
||||
# Cleanup
|
||||
#
|
||||
SET GLOBAL rpl_semi_sync_master_enabled = 0;
|
||||
DROP TABLE t1;
|
||||
SET @@global.rpl_semi_sync_master_timeout = 10000;
|
||||
SET @@global.rpl_semi_sync_master_wait_no_slave = 1;
|
||||
SET @@global.rpl_semi_sync_master_wait_point = AFTER_COMMIT;
|
@ -59,7 +59,6 @@ show variables like 'rpl_semi_sync_master_enabled';
|
||||
echo [ status of semi-sync on master should be ON even without any semi-sync slaves ];
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
--replace_result 305 304
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
|
||||
--echo #
|
||||
@ -120,7 +119,6 @@ echo [ initial master state after the semi-sync slave connected ];
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
--replace_result 305 304
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
|
||||
replace_result $engine_type ENGINE_TYPE;
|
||||
@ -129,7 +127,6 @@ eval create table t1(a int) engine = $engine_type;
|
||||
echo [ master state after CREATE TABLE statement ];
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
--replace_result 305 304
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
|
||||
# After fix of BUG#45848, semi-sync slave should not create any extra
|
||||
@ -153,7 +150,6 @@ insert t1 values (1);
|
||||
echo [ master status after inserts ];
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
--replace_result 305 304
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
|
||||
sync_slave_with_master;
|
||||
@ -302,14 +298,12 @@ source include/stop_slave.inc;
|
||||
connection master;
|
||||
echo [ Semi-sync master status variables before FLUSH STATUS ];
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx';
|
||||
--replace_result 306 305
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';
|
||||
# Do not write the FLUSH STATUS to binlog, to make sure we'll get a
|
||||
# clean status after this.
|
||||
FLUSH NO_WRITE_TO_BINLOG STATUS;
|
||||
echo [ Semi-sync master status variables after FLUSH STATUS ];
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx';
|
||||
--replace_result 306 305
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';
|
||||
|
||||
connection master;
|
||||
@ -358,7 +352,6 @@ reset master;
|
||||
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
--replace_result 306 305
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
|
||||
connection slave;
|
||||
@ -410,7 +403,6 @@ echo [ on master ];
|
||||
echo [ master semi-sync status should be ON ];
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
--replace_result 306 305
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
|
||||
--echo #
|
||||
@ -460,7 +452,6 @@ echo [ master semi-sync should be ON ];
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
--replace_result 306 305
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
insert into t1 values (4);
|
||||
insert into t1 values (5);
|
||||
@ -468,7 +459,6 @@ echo [ master semi-sync should be ON ];
|
||||
show status like 'Rpl_semi_sync_master_clients';
|
||||
show status like 'Rpl_semi_sync_master_status';
|
||||
show status like 'Rpl_semi_sync_master_no_tx';
|
||||
--replace_result 306 305
|
||||
show status like 'Rpl_semi_sync_master_yes_tx';
|
||||
|
||||
--echo #
|
||||
|
4
mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test
Normal file
4
mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test
Normal file
@ -0,0 +1,4 @@
|
||||
--source include/have_binlog_format_statement.inc
|
||||
set global rpl_semi_sync_master_wait_point=AFTER_SYNC;
|
||||
source rpl_semi_sync.test;
|
||||
set global rpl_semi_sync_master_wait_point=default;
|
4
mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test
Normal file
4
mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test
Normal file
@ -0,0 +1,4 @@
|
||||
--source include/have_binlog_format_row.inc
|
||||
set global rpl_semi_sync_master_wait_point=AFTER_SYNC;
|
||||
source rpl_semi_sync.test;
|
||||
set global rpl_semi_sync_master_wait_point=default;
|
@ -0,0 +1 @@
|
||||
--max-connections=40
|
@ -0,0 +1,3 @@
|
||||
set global rpl_semi_sync_master_wait_point=AFTER_SYNC;
|
||||
source rpl_semi_sync_event.test;
|
||||
set global rpl_semi_sync_master_wait_point=default;
|
1
mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt
Normal file
1
mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt
Normal file
@ -0,0 +1 @@
|
||||
--log_bin
|
254
mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test
Normal file
254
mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test
Normal file
@ -0,0 +1,254 @@
|
||||
source include/have_semisync.inc;
|
||||
source include/not_embedded.inc;
|
||||
source include/have_innodb.inc;
|
||||
|
||||
#
|
||||
# This test the rpl_semi_sync_master_wait_point functionality
|
||||
# and illustrates the differences between the two values AFTER_COMMIT and
|
||||
# AFTER_SYNC
|
||||
#
|
||||
|
||||
--echo #
|
||||
--echo # Preparation
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (i INT NOT NULL, PRIMARY KEY (i)) ENGINE=InnoDB;
|
||||
RESET MASTER;
|
||||
|
||||
let $save_timeout = `select @@global.rpl_semi_sync_master_timeout`;
|
||||
let $save_wait_no_slave = `select @@global.rpl_semi_sync_master_wait_no_slave`;
|
||||
let $save_wait_point = `select @@global.rpl_semi_sync_master_wait_point`;
|
||||
|
||||
SET @@global.rpl_semi_sync_master_timeout = 60000;
|
||||
SET @@global.rpl_semi_sync_master_wait_no_slave = 1;
|
||||
|
||||
--echo # It's okay to see "Killed" but we should not see "Timeout" in the log.
|
||||
call mtr.add_suppression("Killed waiting for reply of binlog");
|
||||
call mtr.add_suppression("Run function 'after_commit' in plugin 'rpl_semi_sync_master' failed");
|
||||
call mtr.add_suppression("Run function 'after_sync' in plugin 'rpl_semi_sync_master' failed");
|
||||
|
||||
--echo #
|
||||
--echo # Test wait point = AFTER_COMMIT
|
||||
--echo #
|
||||
SET @@global.rpl_semi_sync_master_wait_point = AFTER_COMMIT;
|
||||
|
||||
--echo # Make another connection to INSERT from.
|
||||
connect (other,localhost,root,,);
|
||||
connection other;
|
||||
let $other_connection_id = `SELECT CONNECTION_ID()`;
|
||||
|
||||
connection default;
|
||||
|
||||
--disable_query_log
|
||||
eval SET @other_connection_id = $other_connection_id;
|
||||
--enable_query_log
|
||||
|
||||
SET GLOBAL rpl_semi_sync_master_enabled = 1;
|
||||
|
||||
--echo # Go ahead and send the INSERT; it should block.
|
||||
connection other;
|
||||
send INSERT INTO t1 (i) VALUES (1);
|
||||
|
||||
connection default;
|
||||
|
||||
let $wait_condition =
|
||||
SELECT COUNT(*) > 0 AS should_be_true
|
||||
FROM information_schema.processlist
|
||||
WHERE id = @other_connection_id
|
||||
AND state = "Waiting for semi-sync ACK from slave";
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo # The INSERT thread should now be waiting.
|
||||
SELECT state AS should_be_waiting
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
|
||||
--echo # The insert should be visible to other threads
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
|
||||
--echo # Kill the waiting thread; it should die immediately.
|
||||
KILL @other_connection_id;
|
||||
|
||||
--echo # Collect the error from the INSERT thread; it should be disconnected.
|
||||
connection other;
|
||||
--error 2013,ER_CONNECTION_KILLED
|
||||
reap;
|
||||
|
||||
connection default;
|
||||
|
||||
--echo # Wait for INSERT thread to actually disappear (KILL closes connection
|
||||
--echo # before thread actually finishes its processing).
|
||||
let $wait_condition =
|
||||
SELECT COUNT(*) = 0 AS should_be_true
|
||||
FROM information_schema.processlist
|
||||
WHERE id = @other_connection_id;
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo # The INSERT thread should now be gone.
|
||||
SELECT state AS should_be_empty_set
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
|
||||
--echo # The insert is still there
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
|
||||
connection default;
|
||||
disconnect other;
|
||||
|
||||
--echo # Make another connection to INSERT from.
|
||||
connect (other,localhost,root,,);
|
||||
connection other;
|
||||
let $other_connection_id = `SELECT CONNECTION_ID()`;
|
||||
connection default;
|
||||
--disable_query_log
|
||||
eval SET @other_connection_id = $other_connection_id;
|
||||
--enable_query_log
|
||||
|
||||
--echo # Go ahead and send the INSERT; it should block.
|
||||
connection other;
|
||||
send INSERT INTO t1 (i) VALUES (2);
|
||||
|
||||
connection default;
|
||||
|
||||
let $wait_condition =
|
||||
SELECT COUNT(*) > 0 AS should_be_true
|
||||
FROM information_schema.processlist
|
||||
WHERE id = @other_connection_id
|
||||
AND state = "Waiting for semi-sync ACK from slave";
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo # The INSERT thread should now be waiting.
|
||||
SELECT state AS should_be_waiting
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
|
||||
--echo # The insert should be visible to other threads
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
|
||||
--echo # Now restart server
|
||||
--source include/restart_mysqld.inc
|
||||
--echo # Done restarting server
|
||||
|
||||
--echo # Reset setting that were lost in restart
|
||||
SET @@global.rpl_semi_sync_master_timeout = 60000;
|
||||
SET @@global.rpl_semi_sync_master_wait_no_slave = 1;
|
||||
|
||||
--echo # Check that row is still there
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
|
||||
disconnect other;
|
||||
|
||||
--echo #
|
||||
--echo # Test wait point = AFTER_SYNC
|
||||
--echo #
|
||||
SET @@global.rpl_semi_sync_master_wait_point = AFTER_SYNC;
|
||||
|
||||
--echo # Make another connection to INSERT from.
|
||||
connect (other,localhost,root,,);
|
||||
connection other;
|
||||
let $other_connection_id = `SELECT CONNECTION_ID()`;
|
||||
|
||||
connection default;
|
||||
|
||||
--disable_query_log
|
||||
eval SET @other_connection_id = $other_connection_id;
|
||||
--enable_query_log
|
||||
|
||||
SET GLOBAL rpl_semi_sync_master_enabled = 1;
|
||||
|
||||
--echo # Go ahead and send the INSERT; it should block.
|
||||
connection other;
|
||||
send INSERT INTO t1 (i) VALUES (3);
|
||||
|
||||
connection default;
|
||||
|
||||
let $wait_condition =
|
||||
SELECT COUNT(*) > 0 AS should_be_true
|
||||
FROM information_schema.processlist
|
||||
WHERE id = @other_connection_id
|
||||
AND state = "Waiting for semi-sync ACK from slave";
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo # The INSERT thread should now be waiting.
|
||||
SELECT state AS should_be_waiting
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
|
||||
--echo # The insert should NOT be visible to other threads
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
|
||||
--echo # Kill the waiting thread; it should die immediately.
|
||||
KILL @other_connection_id;
|
||||
|
||||
--echo # Collect the error from the INSERT thread; it should be disconnected.
|
||||
connection other;
|
||||
--error 2013,ER_CONNECTION_KILLED
|
||||
reap;
|
||||
|
||||
connection default;
|
||||
|
||||
--echo # Wait for INSERT thread to actually disappear (KILL closes connection
|
||||
--echo # before thread actually finishes its processing).
|
||||
let $wait_condition =
|
||||
SELECT COUNT(*) = 0 AS should_be_true
|
||||
FROM information_schema.processlist
|
||||
WHERE id = @other_connection_id;
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo # The INSERT thread should now be gone.
|
||||
SELECT state AS should_be_empty_set
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
|
||||
--echo # The row inserted is there
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
|
||||
connection default;
|
||||
disconnect other;
|
||||
|
||||
--echo # Make another connection to INSERT from.
|
||||
connect (other,localhost,root,,);
|
||||
connection other;
|
||||
let $other_connection_id = `SELECT CONNECTION_ID()`;
|
||||
connection default;
|
||||
--disable_query_log
|
||||
eval SET @other_connection_id = $other_connection_id;
|
||||
--enable_query_log
|
||||
|
||||
--echo # Go ahead and send the INSERT; it should block.
|
||||
connection other;
|
||||
send INSERT INTO t1 (i) VALUES (4);
|
||||
|
||||
connection default;
|
||||
|
||||
let $wait_condition =
|
||||
SELECT COUNT(*) > 0 AS should_be_true
|
||||
FROM information_schema.processlist
|
||||
WHERE id = @other_connection_id
|
||||
AND state = "Waiting for semi-sync ACK from slave";
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo # The INSERT thread should now be waiting.
|
||||
SELECT state AS should_be_waiting
|
||||
FROM information_schema.processlist WHERE id = @other_connection_id;
|
||||
|
||||
--echo # The insert should NOT be visible to other threads
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
|
||||
--echo # Now restart server
|
||||
--source include/restart_mysqld.inc
|
||||
--echo # Done restarting server
|
||||
|
||||
--echo # Reset setting that were lost in restart
|
||||
SET @@global.rpl_semi_sync_master_timeout = 60000;
|
||||
SET @@global.rpl_semi_sync_master_wait_no_slave = 1;
|
||||
|
||||
--echo # But the row inserted is there
|
||||
SELECT * FROM t1 ORDER BY 1;
|
||||
|
||||
disconnect other;
|
||||
|
||||
--echo #
|
||||
--echo # Cleanup
|
||||
--echo #
|
||||
SET GLOBAL rpl_semi_sync_master_enabled = 0;
|
||||
DROP TABLE t1;
|
||||
|
||||
eval SET @@global.rpl_semi_sync_master_timeout = $save_timeout;
|
||||
eval SET @@global.rpl_semi_sync_master_wait_no_slave = $save_wait_no_slave;
|
||||
eval SET @@global.rpl_semi_sync_master_wait_point = $save_wait_point;
|
@ -0,0 +1,46 @@
|
||||
select @@global.rpl_semi_sync_master_wait_point;
|
||||
@@global.rpl_semi_sync_master_wait_point
|
||||
AFTER_COMMIT
|
||||
SET @start_global_value = @@global.rpl_semi_sync_master_wait_point;
|
||||
select @@session.rpl_semi_sync_master_wait_point;
|
||||
ERROR HY000: Variable 'rpl_semi_sync_master_wait_point' is a GLOBAL variable
|
||||
show global variables like 'rpl_semi_sync_master_wait_point';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_wait_point AFTER_COMMIT
|
||||
show session variables like 'rpl_semi_sync_master_wait_point';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_wait_point AFTER_COMMIT
|
||||
select * from information_schema.global_variables where variable_name='rpl_semi_sync_master_wait_point';
|
||||
VARIABLE_NAME VARIABLE_VALUE
|
||||
RPL_SEMI_SYNC_MASTER_WAIT_POINT AFTER_COMMIT
|
||||
select * from information_schema.session_variables where variable_name='rpl_semi_sync_master_wait_point';
|
||||
VARIABLE_NAME VARIABLE_VALUE
|
||||
RPL_SEMI_SYNC_MASTER_WAIT_POINT AFTER_COMMIT
|
||||
set global rpl_semi_sync_master_wait_point=AFTER_SYNC;
|
||||
set session rpl_semi_sync_master_wait_point=AFTER_COMMIT;
|
||||
ERROR HY000: Variable 'rpl_semi_sync_master_wait_point' is a GLOBAL variable and should be set with SET GLOBAL
|
||||
select @@global.rpl_semi_sync_master_wait_point;
|
||||
@@global.rpl_semi_sync_master_wait_point
|
||||
AFTER_SYNC
|
||||
select @@session.rpl_semi_sync_master_wait_point;
|
||||
ERROR HY000: Variable 'rpl_semi_sync_master_wait_point' is a GLOBAL variable
|
||||
show global variables like 'rpl_semi_sync_master_wait_point';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_wait_point AFTER_SYNC
|
||||
show session variables like 'rpl_semi_sync_master_wait_point';
|
||||
Variable_name Value
|
||||
rpl_semi_sync_master_wait_point AFTER_SYNC
|
||||
select * from information_schema.global_variables where variable_name='rpl_semi_sync_master_wait_point';
|
||||
VARIABLE_NAME VARIABLE_VALUE
|
||||
RPL_SEMI_SYNC_MASTER_WAIT_POINT AFTER_SYNC
|
||||
select * from information_schema.session_variables where variable_name='rpl_semi_sync_master_wait_point';
|
||||
VARIABLE_NAME VARIABLE_VALUE
|
||||
RPL_SEMI_SYNC_MASTER_WAIT_POINT AFTER_SYNC
|
||||
set global rpl_semi_sync_master_wait_point=1.1;
|
||||
ERROR 42000: Incorrect argument type to variable 'rpl_semi_sync_master_wait_point'
|
||||
set global rpl_semi_sync_master_wait_point=1e1;
|
||||
ERROR 42000: Incorrect argument type to variable 'rpl_semi_sync_master_wait_point'
|
||||
SET @@global.rpl_semi_sync_master_wait_point = @start_global_value;
|
||||
select @@global.rpl_semi_sync_master_wait_point;
|
||||
@@global.rpl_semi_sync_master_wait_point
|
||||
AFTER_COMMIT
|
@ -0,0 +1,40 @@
|
||||
source include/not_embedded.inc;
|
||||
source include/have_semisync.inc;
|
||||
select @@global.rpl_semi_sync_master_wait_point;
|
||||
SET @start_global_value = @@global.rpl_semi_sync_master_wait_point;
|
||||
|
||||
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||
select @@session.rpl_semi_sync_master_wait_point;
|
||||
show global variables like 'rpl_semi_sync_master_wait_point';
|
||||
show session variables like 'rpl_semi_sync_master_wait_point';
|
||||
select * from information_schema.global_variables where variable_name='rpl_semi_sync_master_wait_point';
|
||||
select * from information_schema.session_variables where variable_name='rpl_semi_sync_master_wait_point';
|
||||
|
||||
#
|
||||
# show that it's writable
|
||||
#
|
||||
set global rpl_semi_sync_master_wait_point=AFTER_SYNC;
|
||||
--error ER_GLOBAL_VARIABLE
|
||||
set session rpl_semi_sync_master_wait_point=AFTER_COMMIT;
|
||||
select @@global.rpl_semi_sync_master_wait_point;
|
||||
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||
select @@session.rpl_semi_sync_master_wait_point;
|
||||
show global variables like 'rpl_semi_sync_master_wait_point';
|
||||
show session variables like 'rpl_semi_sync_master_wait_point';
|
||||
select * from information_schema.global_variables where variable_name='rpl_semi_sync_master_wait_point';
|
||||
select * from information_schema.session_variables where variable_name='rpl_semi_sync_master_wait_point';
|
||||
|
||||
#
|
||||
# incorrect types
|
||||
#
|
||||
--error ER_WRONG_TYPE_FOR_VAR
|
||||
set global rpl_semi_sync_master_wait_point=1.1;
|
||||
--error ER_WRONG_TYPE_FOR_VAR
|
||||
set global rpl_semi_sync_master_wait_point=1e1;
|
||||
|
||||
|
||||
#
|
||||
# Cleanup
|
||||
#
|
||||
SET @@global.rpl_semi_sync_master_wait_point = @start_global_value;
|
||||
select @@global.rpl_semi_sync_master_wait_point;
|
@ -24,6 +24,8 @@
|
||||
|
||||
/* This indicates whether semi-synchronous replication is enabled. */
|
||||
char rpl_semi_sync_master_enabled;
|
||||
unsigned long rpl_semi_sync_master_wait_point =
|
||||
SEMI_SYNC_MASTER_WAIT_POINT_AFTER_STORAGE_COMMIT;
|
||||
unsigned long rpl_semi_sync_master_timeout;
|
||||
unsigned long rpl_semi_sync_master_trace_level;
|
||||
char rpl_semi_sync_master_status = 0;
|
||||
|
@ -594,9 +594,15 @@ class ReplSemiSyncMaster
|
||||
int resetMaster();
|
||||
};
|
||||
|
||||
enum rpl_semi_sync_master_wait_point_t {
|
||||
SEMI_SYNC_MASTER_WAIT_POINT_AFTER_BINLOG_SYNC,
|
||||
SEMI_SYNC_MASTER_WAIT_POINT_AFTER_STORAGE_COMMIT,
|
||||
};
|
||||
|
||||
/* System and status variables for the master component */
|
||||
extern char rpl_semi_sync_master_enabled;
|
||||
extern char rpl_semi_sync_master_status;
|
||||
extern unsigned long rpl_semi_sync_master_wait_point;
|
||||
extern unsigned long rpl_semi_sync_master_clients;
|
||||
extern unsigned long rpl_semi_sync_master_timeout;
|
||||
extern unsigned long rpl_semi_sync_master_trace_level;
|
||||
|
@ -48,8 +48,27 @@ int repl_semi_request_commit(Trans_param *param)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int repl_semi_report_binlog_sync(Binlog_storage_param *param,
|
||||
const char *log_file,
|
||||
my_off_t log_pos, uint32 flags)
|
||||
{
|
||||
int error= 0;
|
||||
if (rpl_semi_sync_master_wait_point ==
|
||||
SEMI_SYNC_MASTER_WAIT_POINT_AFTER_BINLOG_SYNC)
|
||||
{
|
||||
error = repl_semisync.commitTrx(log_file, log_pos);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int repl_semi_report_commit(Trans_param *param)
|
||||
{
|
||||
if (rpl_semi_sync_master_wait_point !=
|
||||
SEMI_SYNC_MASTER_WAIT_POINT_AFTER_STORAGE_COMMIT)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool is_real_trans= param->flags & TRANS_IS_REAL_TRANS;
|
||||
|
||||
@ -175,6 +194,33 @@ static MYSQL_SYSVAR_BOOL(enabled, rpl_semi_sync_master_enabled,
|
||||
&fix_rpl_semi_sync_master_enabled, // update
|
||||
0);
|
||||
|
||||
/* NOTE: must match order of rpl_semi_sync_master_wait_point_t */
|
||||
static const char *rpl_semi_sync_master_wait_point_names[] =
|
||||
{
|
||||
"AFTER_SYNC",
|
||||
"AFTER_COMMIT",
|
||||
NullS
|
||||
};
|
||||
|
||||
static TYPELIB rpl_semi_sync_master_wait_point_typelib =
|
||||
{
|
||||
array_elements(rpl_semi_sync_master_wait_point_names) - 1,
|
||||
"",
|
||||
rpl_semi_sync_master_wait_point_names,
|
||||
NULL
|
||||
};
|
||||
|
||||
static MYSQL_SYSVAR_ENUM(
|
||||
wait_point,
|
||||
rpl_semi_sync_master_wait_point,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"Should transaction wait for semi-sync ack after having synced binlog, "
|
||||
"or after having committed in storeage engine.",
|
||||
NULL, // check
|
||||
NULL, // update
|
||||
SEMI_SYNC_MASTER_WAIT_POINT_AFTER_STORAGE_COMMIT,
|
||||
&rpl_semi_sync_master_wait_point_typelib);
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(timeout, rpl_semi_sync_master_timeout,
|
||||
PLUGIN_VAR_OPCMDARG,
|
||||
"The timeout value (in ms) for semi-synchronous replication in the master",
|
||||
@ -198,6 +244,7 @@ static MYSQL_SYSVAR_ULONG(trace_level, rpl_semi_sync_master_trace_level,
|
||||
|
||||
static SYS_VAR* semi_sync_master_system_vars[]= {
|
||||
MYSQL_SYSVAR(enabled),
|
||||
MYSQL_SYSVAR(wait_point),
|
||||
MYSQL_SYSVAR(timeout),
|
||||
MYSQL_SYSVAR(wait_no_slave),
|
||||
MYSQL_SYSVAR(trace_level),
|
||||
@ -256,6 +303,7 @@ Binlog_storage_observer storage_observer = {
|
||||
sizeof(Binlog_storage_observer), // len
|
||||
|
||||
repl_semi_report_binlog_update, // report_update
|
||||
repl_semi_report_binlog_sync, // after_sync
|
||||
};
|
||||
|
||||
Binlog_transmit_observer transmit_observer = {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "sql_acl.h" // SUPER_ACL
|
||||
#include "sql_base.h" // free_io_cache
|
||||
#include "discover.h" // extension_based_table_discovery, etc
|
||||
#include "log.h" // for assert_LOCK_log_owner
|
||||
#include "log_event.h" // *_rows_log_event
|
||||
#include "create_options.h"
|
||||
#include "rpl_filter.h"
|
||||
@ -1479,6 +1480,12 @@ int ha_commit_trans(THD *thd, bool all)
|
||||
|
||||
done:
|
||||
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
|
||||
|
||||
/* documentation of which mutexes are (not) owned */
|
||||
mysql_mutex_assert_not_owner(&LOCK_prepare_ordered);
|
||||
assert_LOCK_log_owner(false);
|
||||
mysql_mutex_assert_not_owner(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
|
||||
RUN_HOOK(transaction, after_commit, (thd, FALSE));
|
||||
goto end;
|
||||
|
||||
|
118
sql/log.cc
118
sql/log.cc
@ -93,6 +93,7 @@ ulong opt_binlog_dbug_fsync_sleep= 0;
|
||||
|
||||
mysql_mutex_t LOCK_prepare_ordered;
|
||||
mysql_cond_t COND_prepare_ordered;
|
||||
mysql_mutex_t LOCK_after_binlog_sync;
|
||||
mysql_mutex_t LOCK_commit_ordered;
|
||||
|
||||
static ulonglong binlog_status_var_num_commits;
|
||||
@ -3938,7 +3939,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log,
|
||||
Without binlog, we cannot XA recover prepared-but-not-committed
|
||||
transactions in engines. So force a commit checkpoint first.
|
||||
|
||||
Note that we take and immediately release LOCK_commit_ordered. This has
|
||||
Note that we take and immediately
|
||||
release LOCK_after_binlog_sync/LOCK_commit_ordered. This has
|
||||
the effect to ensure that any on-going group commit (in
|
||||
trx_group_commit_leader()) has completed before we request the checkpoint,
|
||||
due to the chaining of LOCK_log and LOCK_commit_ordered in that function.
|
||||
@ -3949,7 +3951,10 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log,
|
||||
commit_ordered() in the engine of some transaction, and then a crash
|
||||
later would leave such transaction not recoverable.
|
||||
*/
|
||||
|
||||
mysql_mutex_lock(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_lock(&LOCK_commit_ordered);
|
||||
mysql_mutex_unlock(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_unlock(&LOCK_commit_ordered);
|
||||
|
||||
mark_xids_active(current_binlog_id, 1);
|
||||
@ -6035,11 +6040,6 @@ err:
|
||||
if ((error= flush_and_sync(&synced)))
|
||||
{
|
||||
}
|
||||
else if ((error= RUN_HOOK(binlog_storage, after_flush,
|
||||
(thd, log_file_name, file->pos_in_file, synced))))
|
||||
{
|
||||
sql_print_error("Failed to run 'after_flush' hooks");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* update binlog_end_pos so it can be read by dump thread
|
||||
@ -6050,23 +6050,58 @@ err:
|
||||
*/
|
||||
update_binlog_end_pos(offset);
|
||||
|
||||
signal_update();
|
||||
if ((error= rotate(false, &check_purge)))
|
||||
check_purge= false;
|
||||
/* documentation of which mutexes are (not) owned */
|
||||
mysql_mutex_assert_not_owner(&LOCK_prepare_ordered);
|
||||
mysql_mutex_assert_owner(&LOCK_log);
|
||||
mysql_mutex_assert_not_owner(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
|
||||
bool first= true;
|
||||
bool last= true;
|
||||
if ((error= RUN_HOOK(binlog_storage, after_flush,
|
||||
(thd, log_file_name, file->pos_in_file,
|
||||
synced, first, last))))
|
||||
{
|
||||
sql_print_error("Failed to run 'after_flush' hooks");
|
||||
error= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
signal_update();
|
||||
if ((error= rotate(false, &check_purge)))
|
||||
check_purge= false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status_var_add(thd->status_var.binlog_bytes_written,
|
||||
offset - my_org_b_tell);
|
||||
|
||||
mysql_mutex_lock(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_unlock(&LOCK_log);
|
||||
|
||||
/* documentation of which mutexes are (not) owned */
|
||||
mysql_mutex_assert_not_owner(&LOCK_prepare_ordered);
|
||||
mysql_mutex_assert_not_owner(&LOCK_log);
|
||||
mysql_mutex_assert_owner(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
|
||||
bool first= true;
|
||||
bool last= true;
|
||||
if (RUN_HOOK(binlog_storage, after_sync,
|
||||
(thd, log_file_name, file->pos_in_file,
|
||||
first, last)))
|
||||
{
|
||||
error=1;
|
||||
/* error is already printed inside hook */
|
||||
}
|
||||
|
||||
/*
|
||||
Take mutex to protect against a reader seeing partial writes of 64-bit
|
||||
offset on 32-bit CPUs.
|
||||
*/
|
||||
mysql_mutex_lock(&LOCK_commit_ordered);
|
||||
mysql_mutex_unlock(&LOCK_after_binlog_sync);
|
||||
last_commit_pos_offset= offset;
|
||||
mysql_mutex_unlock(&LOCK_commit_ordered);
|
||||
mysql_mutex_unlock(&LOCK_log);
|
||||
|
||||
if (check_purge)
|
||||
checkpoint_and_purge(prev_binlog_id);
|
||||
@ -7374,13 +7409,22 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
|
||||
{
|
||||
bool any_error= false;
|
||||
bool all_error= true;
|
||||
|
||||
/* documentation of which mutexes are (not) owned */
|
||||
mysql_mutex_assert_not_owner(&LOCK_prepare_ordered);
|
||||
mysql_mutex_assert_owner(&LOCK_log);
|
||||
mysql_mutex_assert_not_owner(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
|
||||
bool first= true, last;
|
||||
for (current= queue; current != NULL; current= current->next)
|
||||
{
|
||||
last= current->next == NULL;
|
||||
if (!current->error &&
|
||||
RUN_HOOK(binlog_storage, after_flush,
|
||||
(current->thd,
|
||||
current->cache_mngr->last_commit_pos_file,
|
||||
current->cache_mngr->last_commit_pos_offset, synced)))
|
||||
current->cache_mngr->last_commit_pos_offset, synced,
|
||||
first, last)))
|
||||
{
|
||||
current->error= ER_ERROR_ON_WRITE;
|
||||
current->commit_errno= -1;
|
||||
@ -7389,6 +7433,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
|
||||
}
|
||||
else
|
||||
all_error= false;
|
||||
first= false;
|
||||
}
|
||||
|
||||
/* update binlog_end_pos so it can be read by dump thread
|
||||
@ -7437,22 +7482,55 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_SYNC(leader->thd, "commit_before_get_LOCK_commit_ordered");
|
||||
mysql_mutex_lock(&LOCK_commit_ordered);
|
||||
/**
|
||||
* TODO(jonaso): Check with Kristian,
|
||||
* if we rotate:d above, this offset is "wrong"
|
||||
*/
|
||||
last_commit_pos_offset= commit_offset;
|
||||
DEBUG_SYNC(leader->thd, "commit_before_get_LOCK_after_binlog_sync");
|
||||
mysql_mutex_lock(&LOCK_after_binlog_sync);
|
||||
/*
|
||||
We cannot unlock LOCK_log until we have locked LOCK_commit_ordered;
|
||||
We cannot unlock LOCK_log until we have locked LOCK_after_binlog_sync;
|
||||
otherwise scheduling could allow the next group commit to run ahead of us,
|
||||
messing up the order of commit_ordered() calls. But as soon as
|
||||
LOCK_commit_ordered is obtained, we can let the next group commit start.
|
||||
LOCK_after_binlog_sync is obtained, we can let the next group commit start.
|
||||
*/
|
||||
mysql_mutex_unlock(&LOCK_log);
|
||||
|
||||
DEBUG_SYNC(leader->thd, "commit_after_release_LOCK_log");
|
||||
|
||||
/*
|
||||
Loop through threads and run the binlog_sync hook
|
||||
*/
|
||||
{
|
||||
/* documentation of which mutexes are (not) owned */
|
||||
mysql_mutex_assert_not_owner(&LOCK_prepare_ordered);
|
||||
mysql_mutex_assert_not_owner(&LOCK_log);
|
||||
mysql_mutex_assert_owner(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
|
||||
|
||||
bool first= true, last;
|
||||
for (current= queue; current != NULL; current= current->next)
|
||||
{
|
||||
last= current->next == NULL;
|
||||
if (!current->error &&
|
||||
RUN_HOOK(binlog_storage, after_sync,
|
||||
(current->thd, log_file_name,
|
||||
current->cache_mngr->last_commit_pos_offset,
|
||||
first, last)))
|
||||
{
|
||||
/* error is already printed inside hook */
|
||||
}
|
||||
first= false;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_SYNC(leader->thd, "commit_before_get_LOCK_commit_ordered");
|
||||
mysql_mutex_lock(&LOCK_commit_ordered);
|
||||
last_commit_pos_offset= commit_offset;
|
||||
|
||||
/*
|
||||
Unlock LOCK_after_binlog_sync only *after* LOCK_commit_ordered has been
|
||||
acquired so that groups can not reorder for the different stages of
|
||||
the group commit procedure.
|
||||
*/
|
||||
mysql_mutex_unlock(&LOCK_after_binlog_sync);
|
||||
DEBUG_SYNC(leader->thd, "commit_after_release_LOCK_after_binlog_sync");
|
||||
++num_group_commits;
|
||||
|
||||
if (!opt_optimize_thread_scheduling)
|
||||
|
@ -88,9 +88,11 @@ protected:
|
||||
*/
|
||||
extern mysql_mutex_t LOCK_prepare_ordered;
|
||||
extern mysql_cond_t COND_prepare_ordered;
|
||||
extern mysql_mutex_t LOCK_after_binlog_sync;
|
||||
extern mysql_mutex_t LOCK_commit_ordered;
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
extern PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered;
|
||||
extern PSI_mutex_key key_LOCK_after_binlog_sync;
|
||||
extern PSI_cond_key key_COND_prepare_ordered;
|
||||
#endif
|
||||
|
||||
@ -1157,4 +1159,6 @@ static inline TC_LOG *get_tc_log_implementation()
|
||||
|
||||
void assert_LOCK_log_owner(bool owner);
|
||||
|
||||
void assert_LOCK_log_owner(bool owner);
|
||||
|
||||
#endif /* LOG_H */
|
||||
|
@ -890,6 +890,7 @@ PSI_mutex_key key_LOCK_stats,
|
||||
key_LOCK_wakeup_ready, key_LOCK_wait_commit;
|
||||
PSI_mutex_key key_LOCK_gtid_waiting;
|
||||
|
||||
PSI_mutex_key key_LOCK_after_binlog_sync;
|
||||
PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered,
|
||||
key_LOCK_slave_init;
|
||||
PSI_mutex_key key_TABLE_SHARE_LOCK_share;
|
||||
@ -954,6 +955,7 @@ static PSI_mutex_info all_server_mutexes[]=
|
||||
{ &key_TABLE_SHARE_LOCK_share, "TABLE_SHARE::LOCK_share", 0},
|
||||
{ &key_LOCK_error_messages, "LOCK_error_messages", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_after_binlog_sync, "LOCK_after_binlog_sync", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_slave_init, "LOCK_slave_init", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOG_INFO_lock, "LOG_INFO::lock", 0},
|
||||
@ -2243,6 +2245,7 @@ static void clean_up_mutexes()
|
||||
mysql_cond_destroy(&COND_server_started);
|
||||
mysql_mutex_destroy(&LOCK_prepare_ordered);
|
||||
mysql_cond_destroy(&COND_prepare_ordered);
|
||||
mysql_mutex_destroy(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_destroy(&LOCK_commit_ordered);
|
||||
mysql_mutex_destroy(&LOCK_slave_init);
|
||||
mysql_cond_destroy(&COND_slave_init);
|
||||
@ -4535,6 +4538,8 @@ static int init_thread_environment()
|
||||
mysql_mutex_init(key_LOCK_prepare_ordered, &LOCK_prepare_ordered,
|
||||
MY_MUTEX_INIT_SLOW);
|
||||
mysql_cond_init(key_COND_prepare_ordered, &COND_prepare_ordered, NULL);
|
||||
mysql_mutex_init(key_LOCK_after_binlog_sync, &LOCK_after_binlog_sync,
|
||||
MY_MUTEX_INIT_SLOW);
|
||||
mysql_mutex_init(key_LOCK_commit_ordered, &LOCK_commit_ordered,
|
||||
MY_MUTEX_INIT_SLOW);
|
||||
mysql_mutex_init(key_LOCK_slave_init, &LOCK_slave_init,
|
||||
|
@ -81,6 +81,7 @@ typedef struct Trans_observer {
|
||||
succeeded.
|
||||
|
||||
@note The return value is currently ignored by the server.
|
||||
@note This hook is called wo/ any global mutex held
|
||||
|
||||
@param param The parameter for transaction observers
|
||||
|
||||
@ -103,6 +104,8 @@ typedef struct Trans_observer {
|
||||
|
||||
@param param The parameter for transaction observers
|
||||
|
||||
@note This hook is called wo/ any global mutex held
|
||||
|
||||
@retval 0 Sucess
|
||||
@retval 1 Failure
|
||||
*/
|
||||
@ -114,7 +117,13 @@ typedef struct Trans_observer {
|
||||
*/
|
||||
enum Binlog_storage_flags {
|
||||
/** Binary log was sync:ed */
|
||||
BINLOG_STORAGE_IS_SYNCED = 1
|
||||
BINLOG_STORAGE_IS_SYNCED = 1,
|
||||
|
||||
/** First(or alone) in a group commit */
|
||||
BINLOG_GROUP_COMMIT_LEADER = 2,
|
||||
|
||||
/** Last(or alone) in a group commit */
|
||||
BINLOG_GROUP_COMMIT_TRAILER = 4
|
||||
};
|
||||
|
||||
/**
|
||||
@ -137,6 +146,8 @@ typedef struct Binlog_storage_observer {
|
||||
binary log file. Whether the binary log file is synchronized to
|
||||
disk is indicated by the bit BINLOG_STORAGE_IS_SYNCED in @a flags.
|
||||
|
||||
@note: this hook is called with LOCK_log mutex held
|
||||
|
||||
@param param Observer common parameter
|
||||
@param log_file Binlog file name been updated
|
||||
@param log_pos Binlog position after update
|
||||
@ -148,6 +159,26 @@ typedef struct Binlog_storage_observer {
|
||||
int (*after_flush)(Binlog_storage_param *param,
|
||||
const char *log_file, my_off_t log_pos,
|
||||
uint32 flags);
|
||||
|
||||
/**
|
||||
This callback is called after binlog has been synced
|
||||
|
||||
This callback is called after events flushed to disk has been sync:ed
|
||||
("group committed").
|
||||
|
||||
@note: this hook is called with LOCK_after_binlog_sync mutex held
|
||||
|
||||
@param param Observer common parameter
|
||||
@param log_file Binlog file name been updated
|
||||
@param log_pos Binlog position after update
|
||||
@param flags flags for binlog storage
|
||||
|
||||
@retval 0 Sucess
|
||||
@retval 1 Failure
|
||||
*/
|
||||
int (*after_sync)(Binlog_storage_param *param,
|
||||
const char *log_file, my_off_t log_pos,
|
||||
uint32 flags);
|
||||
} Binlog_storage_observer;
|
||||
|
||||
/**
|
||||
|
@ -252,12 +252,18 @@ int Trans_delegate::after_rollback(THD *thd, bool all)
|
||||
int Binlog_storage_delegate::after_flush(THD *thd,
|
||||
const char *log_file,
|
||||
my_off_t log_pos,
|
||||
bool synced)
|
||||
bool synced,
|
||||
bool first_in_group,
|
||||
bool last_in_group)
|
||||
{
|
||||
Binlog_storage_param param;
|
||||
uint32 flags=0;
|
||||
if (synced)
|
||||
flags |= BINLOG_STORAGE_IS_SYNCED;
|
||||
if (first_in_group)
|
||||
flags|= BINLOG_GROUP_COMMIT_LEADER;
|
||||
if (last_in_group)
|
||||
flags|= BINLOG_GROUP_COMMIT_TRAILER;
|
||||
|
||||
Trans_binlog_info *log_info=
|
||||
my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
|
||||
@ -279,6 +285,27 @@ int Binlog_storage_delegate::after_flush(THD *thd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Binlog_storage_delegate::after_sync(THD *thd,
|
||||
const char *log_file,
|
||||
my_off_t log_pos,
|
||||
bool first_in_group,
|
||||
bool last_in_group)
|
||||
{
|
||||
Binlog_storage_param param;
|
||||
uint32 flags=0;
|
||||
|
||||
if (first_in_group)
|
||||
flags|= BINLOG_GROUP_COMMIT_LEADER;
|
||||
if (last_in_group)
|
||||
flags|= BINLOG_GROUP_COMMIT_TRAILER;
|
||||
|
||||
int ret= 0;
|
||||
FOREACH_OBSERVER(ret, after_sync, thd,
|
||||
(¶m, log_file+dirname_length(log_file), log_pos, flags));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
int Binlog_transmit_delegate::transmit_start(THD *thd, ushort flags,
|
||||
const char *log_file,
|
||||
|
@ -153,7 +153,10 @@ class Binlog_storage_delegate
|
||||
public:
|
||||
typedef Binlog_storage_observer Observer;
|
||||
int after_flush(THD *thd, const char *log_file,
|
||||
my_off_t log_pos, bool synced);
|
||||
my_off_t log_pos, bool synced,
|
||||
bool first_in_group, bool last_in_group);
|
||||
int after_sync(THD *thd, const char *log_file, my_off_t log_pos,
|
||||
bool first_in_group, bool last_in_group);
|
||||
};
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "rpl_handler.h"
|
||||
#include "debug_sync.h" // DEBUG_SYNC
|
||||
#include "sql_acl.h"
|
||||
#include "log.h" // for assert_LOCK_log_owner
|
||||
|
||||
/* Conditions under which the transaction state must not change. */
|
||||
static bool trans_check(THD *thd)
|
||||
@ -232,6 +233,13 @@ bool trans_commit(THD *thd)
|
||||
~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
|
||||
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
|
||||
res= ha_commit_trans(thd, TRUE);
|
||||
|
||||
/* documentation of which mutexes are (not) owned */
|
||||
mysql_mutex_assert_not_owner(&LOCK_prepare_ordered);
|
||||
assert_LOCK_log_owner(false);
|
||||
mysql_mutex_assert_not_owner(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
|
||||
|
||||
if (WSREP_ON)
|
||||
wsrep_post_commit(thd, TRUE);
|
||||
/*
|
||||
@ -433,6 +441,12 @@ bool trans_commit_stmt(THD *thd)
|
||||
}
|
||||
}
|
||||
|
||||
/* documentation of which mutexes are (not) owned */
|
||||
mysql_mutex_assert_not_owner(&LOCK_prepare_ordered);
|
||||
assert_LOCK_log_owner(false);
|
||||
mysql_mutex_assert_not_owner(&LOCK_after_binlog_sync);
|
||||
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
|
||||
|
||||
/*
|
||||
if res is non-zero, then ha_commit_trans has rolled back the
|
||||
transaction, so the hooks for rollback will be called.
|
||||
|
Reference in New Issue
Block a user