diff options
29 files changed, 1735 insertions, 46 deletions
diff --git a/mysql-test/suite/innodb/r/group_commit.result b/mysql-test/suite/innodb/r/group_commit.result index 1009a83637f..5321715df36 100644 --- a/mysql-test/suite/innodb/r/group_commit.result +++ b/mysql-test/suite/innodb/r/group_commit.result @@ -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"); diff --git a/mysql-test/suite/innodb/r/group_commit_no_optimize_thread.result b/mysql-test/suite/innodb/r/group_commit_no_optimize_thread.result index 34a638da2d5..dd152fd3c9c 100644 --- a/mysql-test/suite/innodb/r/group_commit_no_optimize_thread.result +++ b/mysql-test/suite/innodb/r/group_commit_no_optimize_thread.result @@ -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"); diff --git a/mysql-test/suite/innodb/t/group_commit.test b/mysql-test/suite/innodb/t/group_commit.test index 07aac2a619e..692e06f38b8 100644 --- a/mysql-test/suite/innodb/t/group_commit.test +++ b/mysql-test/suite/innodb/t/group_commit.test @@ -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"); diff --git a/mysql-test/suite/innodb/t/group_commit_no_optimize_thread.test b/mysql-test/suite/innodb/t/group_commit_no_optimize_thread.test index 7bee6b8b177..85c0e295424 100644 --- a/mysql-test/suite/innodb/t/group_commit_no_optimize_thread.test +++ b/mysql-test/suite/innodb/t/group_commit_no_optimize_thread.test @@ -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"); diff --git a/mysql-test/suite/perfschema/r/dml_setup_instruments.result b/mysql-test/suite/perfschema/r/dml_setup_instruments.result index b264a075eba..08edb1c3b01 100644 --- a/mysql-test/suite/perfschema/r/dml_setup_instruments.result +++ b/mysql-test/suite/perfschema/r/dml_setup_instruments.result @@ -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') diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_after_sync.result b/mysql-test/suite/rpl/r/rpl_semi_sync_after_sync.result new file mode 100644 index 00000000000..708c3ef0313 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync_after_sync.result @@ -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; diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_after_sync_row.result b/mysql-test/suite/rpl/r/rpl_semi_sync_after_sync_row.result new file mode 100644 index 00000000000..3a9ab6cedca --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync_after_sync_row.result @@ -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; diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_event_after_sync.result b/mysql-test/suite/rpl/r/rpl_semi_sync_event_after_sync.result new file mode 100644 index 00000000000..4533e7fb4ac --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync_event_after_sync.result @@ -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; diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_wait_point.result b/mysql-test/suite/rpl/r/rpl_semi_sync_wait_point.result new file mode 100644 index 00000000000..36a6ea655a2 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync_wait_point.result @@ -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; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync.test b/mysql-test/suite/rpl/t/rpl_semi_sync.test index aa36d70d4b7..a9ea4985039 100644 --- a/mysql-test/suite/rpl/t/rpl_semi_sync.test +++ b/mysql-test/suite/rpl/t/rpl_semi_sync.test @@ -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 # diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test b/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test new file mode 100644 index 00000000000..2d91d2e4118 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test @@ -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; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test b/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test new file mode 100644 index 00000000000..47af6c34fcf --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test @@ -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; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync-master.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync-master.opt new file mode 100644 index 00000000000..4cfb5d53923 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync-master.opt @@ -0,0 +1 @@ +--max-connections=40 diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync.test b/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync.test new file mode 100644 index 00000000000..527900fd949 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync.test @@ -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; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt new file mode 100644 index 00000000000..e49ae455124 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt @@ -0,0 +1 @@ +--log_bin diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test new file mode 100644 index 00000000000..6e4dc456a27 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test @@ -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; diff --git a/mysql-test/suite/sys_vars/r/rpl_semi_sync_master_wait_point_basic.result b/mysql-test/suite/sys_vars/r/rpl_semi_sync_master_wait_point_basic.result new file mode 100644 index 00000000000..4900086e9ab --- /dev/null +++ b/mysql-test/suite/sys_vars/r/rpl_semi_sync_master_wait_point_basic.result @@ -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 diff --git a/mysql-test/suite/sys_vars/t/rpl_semi_sync_master_wait_point_basic.test b/mysql-test/suite/sys_vars/t/rpl_semi_sync_master_wait_point_basic.test new file mode 100644 index 00000000000..8125cf8d653 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/rpl_semi_sync_master_wait_point_basic.test @@ -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; diff --git a/plugin/semisync/semisync_master.cc b/plugin/semisync/semisync_master.cc index bb9eb96f6d7..55f81057d03 100644 --- a/plugin/semisync/semisync_master.cc +++ b/plugin/semisync/semisync_master.cc @@ -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; diff --git a/plugin/semisync/semisync_master.h b/plugin/semisync/semisync_master.h index 66fa176624b..d9dc4ce024b 100644 --- a/plugin/semisync/semisync_master.h +++ b/plugin/semisync/semisync_master.h @@ -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; diff --git a/plugin/semisync/semisync_master_plugin.cc b/plugin/semisync/semisync_master_plugin.cc index 9eae7f03c34..7bb0eea44ee 100644 --- a/plugin/semisync/semisync_master_plugin.cc +++ b/plugin/semisync/semisync_master_plugin.cc @@ -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 = { diff --git a/sql/handler.cc b/sql/handler.cc index c1363cfcaf1..4bb8e0b4397 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -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; diff --git a/sql/log.cc b/sql/log.cc index edb4c07c8cc..66e142668a9 100644 --- a/sql/log.cc +++ b/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) diff --git a/sql/log.h b/sql/log.h index 21af7d08959..9b6f365eea7 100644 --- a/sql/log.h +++ b/sql/log.h @@ -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 */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1bf91a9f965..07b4f1da3b1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -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, diff --git a/sql/replication.h b/sql/replication.h index 9f9cc9eadfc..4731c2246ef 100644 --- a/sql/replication.h +++ b/sql/replication.h @@ -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; /** diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc index 09e221e9bd5..2c388e572f9 100644 --- a/sql/rpl_handler.cc +++ b/sql/rpl_handler.cc @@ -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, diff --git a/sql/rpl_handler.h b/sql/rpl_handler.h index e262ebdbd6b..afcfd9d55b1 100644 --- a/sql/rpl_handler.h +++ b/sql/rpl_handler.h @@ -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 diff --git a/sql/transaction.cc b/sql/transaction.cc index 5127d241e85..3628790aa63 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -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. |