=== modified file 'mysql-test/suite/innodb/r/group_commit.result'
--- mysql-test/suite/innodb/r/group_commit.result	2011-10-19 19:45:18 +0000
+++ mysql-test/suite/innodb/r/group_commit.result	2014-10-20 09:25:13 +0000
@@ -3,11 +3,11 @@
 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 @@
 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");

=== modified file 'mysql-test/suite/innodb/r/group_commit_no_optimize_thread.result'
--- mysql-test/suite/innodb/r/group_commit_no_optimize_thread.result	2011-10-19 19:45:18 +0000
+++ mysql-test/suite/innodb/r/group_commit_no_optimize_thread.result	2014-10-20 09:25:13 +0000
@@ -3,11 +3,11 @@
 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 @@
 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");

=== modified file 'mysql-test/suite/innodb/t/group_commit.test'
--- mysql-test/suite/innodb/t/group_commit.test	2012-02-07 15:22:36 +0000
+++ mysql-test/suite/innodb/t/group_commit.test	2014-10-20 09:25:13 +0000
@@ -27,7 +27,7 @@
 # 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 @@
 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 @@
 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");

=== modified file 'mysql-test/suite/innodb/t/group_commit_no_optimize_thread.test'
--- mysql-test/suite/innodb/t/group_commit_no_optimize_thread.test	2012-02-07 15:22:36 +0000
+++ mysql-test/suite/innodb/t/group_commit_no_optimize_thread.test	2014-10-20 09:25:13 +0000
@@ -27,7 +27,7 @@
 # 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 @@
 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 @@
 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");

=== added file 'mysql-test/suite/rpl/r/rpl_semi_sync_after_sync.result'
--- mysql-test/suite/rpl/r/rpl_semi_sync_after_sync.result	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/r/rpl_semi_sync_after_sync.result	2014-10-20 10:58:50 +0000
@@ -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;

=== added file 'mysql-test/suite/rpl/r/rpl_semi_sync_after_sync_row.result'
--- mysql-test/suite/rpl/r/rpl_semi_sync_after_sync_row.result	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/r/rpl_semi_sync_after_sync_row.result	2014-10-20 11:06:10 +0000
@@ -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;

=== added file 'mysql-test/suite/rpl/r/rpl_semi_sync_event_after_sync.result'
--- mysql-test/suite/rpl/r/rpl_semi_sync_event_after_sync.result	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/r/rpl_semi_sync_event_after_sync.result	2014-10-20 09:25:13 +0000
@@ -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;

=== added file 'mysql-test/suite/rpl/r/rpl_semi_sync_wait_point.result'
--- mysql-test/suite/rpl/r/rpl_semi_sync_wait_point.result	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/r/rpl_semi_sync_wait_point.result	2014-10-20 09:25:13 +0000
@@ -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.
+ERROR HY000: Lost connection to MySQL server during query
+# 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.
+ERROR HY000: Lost connection to MySQL server during query
+# 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;

=== modified file 'mysql-test/suite/rpl/t/rpl_semi_sync.test'
--- mysql-test/suite/rpl/t/rpl_semi_sync.test	2014-08-07 16:06:56 +0000
+++ mysql-test/suite/rpl/t/rpl_semi_sync.test	2014-10-20 10:52:49 +0000
@@ -59,7 +59,6 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 
 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 [ 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 @@
 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 @@
 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 #

=== added file 'mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test'
--- mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test	2014-10-20 09:25:13 +0000
@@ -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;

=== added file 'mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test'
--- mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test	2014-10-20 09:25:13 +0000
@@ -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;

=== added file 'mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync-master.opt'
--- mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync-master.opt	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync-master.opt	2014-10-20 09:25:13 +0000
@@ -0,0 +1,1 @@
+--max-connections=40

=== added file 'mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync.test'
--- mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync.test	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync.test	2014-10-20 09:25:13 +0000
@@ -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;

=== added file 'mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt'
--- mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt	2014-10-20 09:25:13 +0000
@@ -0,0 +1,1 @@
+--log_bin

=== added file 'mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test'
--- mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test	1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test	2014-10-20 09:25:13 +0000
@@ -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
+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
+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;

=== modified file 'plugin/semisync/semisync_master.cc'
--- plugin/semisync/semisync_master.cc	2014-02-03 14:22:39 +0000
+++ plugin/semisync/semisync_master.cc	2014-10-20 09:25:13 +0000
@@ -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;

=== modified file 'plugin/semisync/semisync_master.h'
--- plugin/semisync/semisync_master.h	2013-09-14 01:09:36 +0000
+++ plugin/semisync/semisync_master.h	2014-10-20 09:25:13 +0000
@@ -594,9 +594,15 @@
   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;

=== modified file 'plugin/semisync/semisync_master_plugin.cc'
--- plugin/semisync/semisync_master_plugin.cc	2014-06-24 19:17:59 +0000
+++ plugin/semisync/semisync_master_plugin.cc	2014-10-20 09:25:13 +0000
@@ -48,8 +48,27 @@
   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 @@
   &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 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 @@
   sizeof(Binlog_storage_observer), // len
 
   repl_semi_report_binlog_update, // report_update
+  repl_semi_report_binlog_sync,   // after_sync
 };
 
 Binlog_transmit_observer transmit_observer = {

=== modified file 'sql/handler.cc'
--- sql/handler.cc	2014-09-30 17:31:14 +0000
+++ sql/handler.cc	2014-10-20 09:27:06 +0000
@@ -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"
@@ -1445,6 +1446,12 @@
 
 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;
 

=== modified file 'sql/log.cc'
--- sql/log.cc	2014-10-09 08:30:11 +0000
+++ sql/log.cc	2014-10-20 09:30:55 +0000
@@ -91,6 +91,7 @@
 
 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;
@@ -3889,7 +3890,8 @@
       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.
@@ -3900,7 +3902,10 @@
       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);
@@ -5972,30 +5977,60 @@
         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
         {
-          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);
@@ -7300,12 +7335,21 @@
     {
       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, log_file_name,
-                 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;
@@ -7314,6 +7358,7 @@
         }
         else
           all_error= false;
+        first= false;
       }
 
       if (any_error)
@@ -7354,18 +7399,54 @@
     }
   }
 
-  DEBUG_SYNC(leader->thd, "commit_before_get_LOCK_commit_ordered");
-  mysql_mutex_lock(&LOCK_commit_ordered);
-  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)
@@ -9675,6 +9756,14 @@
   }
 }
 
+void assert_LOCK_log_owner(bool owner)
+{
+  if (owner)
+    mysql_mutex_assert_owner(mysql_bin_log.get_log_lock());
+  else
+    mysql_mutex_assert_not_owner(mysql_bin_log.get_log_lock());
+}
+
 struct st_mysql_storage_engine binlog_storage_engine=
 { MYSQL_HANDLERTON_INTERFACE_VERSION };
 

=== modified file 'sql/log.h'
--- sql/log.h	2014-08-07 16:06:56 +0000
+++ sql/log.h	2014-10-20 09:25:13 +0000
@@ -86,9 +86,11 @@
 */
 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
 
@@ -339,6 +341,9 @@
   /** Instrumentation key to use for file io in @c log_file */
   PSI_file_key m_log_file_key;
 #endif
+
+  /* for documentation of mutexes held in various places in code */
+  friend void assert_LOCK_log_owner(bool owner);
 };
 
 class MYSQL_QUERY_LOG: public MYSQL_LOG
@@ -1086,4 +1091,6 @@
   return &tc_log_mmap;
 }
 
+void assert_LOCK_log_owner(bool owner);
+
 #endif /* LOG_H */

=== modified file 'sql/mysqld.cc'
--- sql/mysqld.cc	2014-10-09 08:30:11 +0000
+++ sql/mysqld.cc	2014-10-20 09:26:09 +0000
@@ -882,6 +882,7 @@
   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;
@@ -946,6 +947,7 @@
   { &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},
@@ -2174,6 +2176,7 @@
   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);
@@ -4413,6 +4416,8 @@
   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,

=== modified file 'sql/replication.h'
--- sql/replication.h	2014-08-07 16:06:56 +0000
+++ sql/replication.h	2014-10-20 09:25:13 +0000
@@ -81,6 +81,7 @@
      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 @@
 
      @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 @@
 */
 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 @@
      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 @@
   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;
 
 /**

=== modified file 'sql/rpl_handler.cc'
--- sql/rpl_handler.cc	2014-09-30 17:31:14 +0000
+++ sql/rpl_handler.cc	2014-10-20 10:48:21 +0000
@@ -252,12 +252,18 @@
 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 @@
   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,
+                   (&param, 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,

=== modified file 'sql/rpl_handler.h'
--- sql/rpl_handler.h	2014-08-07 16:06:56 +0000
+++ sql/rpl_handler.h	2014-10-20 09:25:13 +0000
@@ -153,7 +153,10 @@
 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

=== modified file 'sql/transaction.cc'
--- sql/transaction.cc	2014-09-30 17:31:14 +0000
+++ sql/transaction.cc	2014-10-20 09:25:13 +0000
@@ -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)
@@ -217,6 +218,13 @@
     ~(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 res is non-zero, then ha_commit_trans has rolled back the
       transaction, so the hooks for rollback will be called.
@@ -399,6 +407,12 @@
     }
   }
 
+  /* 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.

