diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_binlog_send_race.result b/mysql-test/suite/rpl/r/rpl_semi_sync_binlog_send_race.result new file mode 100644 index 00000000000..9969275e0c5 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync_binlog_send_race.result @@ -0,0 +1,21 @@ +include/master-slave.inc +Warnings: +Note #### Sending passwords in plain text without SSL/TLS is extremely insecure. +Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information. +[connection master] +include/install_semisync.inc +include/stop_slave.inc +change master to master_heartbeat_period = 0.1; +include/start_slave.inc +create table t1 (a int); +set @@global.debug= '+d,simulate_delay_in_binlog_signal_update'; +insert into t1 values (1); +set @@global.debug= '-d,simulate_delay_in_binlog_signal_update'; +insert into t1 values (1); +insert into t1 values (1); +include/uninstall_semisync.inc +include/stop_slave.inc +include/start_slave.inc +DROP TABLE t1; +include/sync_slave_sql_with_master.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_binlog_send_race-master.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_binlog_send_race-master.opt new file mode 100644 index 00000000000..58029d28ace --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_binlog_send_race-master.opt @@ -0,0 +1 @@ +$SEMISYNC_PLUGIN_OPT diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_binlog_send_race-slave.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_binlog_send_race-slave.opt new file mode 100644 index 00000000000..58029d28ace --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_binlog_send_race-slave.opt @@ -0,0 +1 @@ +$SEMISYNC_PLUGIN_OPT diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_binlog_send_race.test b/mysql-test/suite/rpl/t/rpl_semi_sync_binlog_send_race.test new file mode 100644 index 00000000000..814c4c614a2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_binlog_send_race.test @@ -0,0 +1,55 @@ +# Test of binlog sender with heartbeat to make sure it doesn't miss signals. +# - Setup semisync repl with short heartbeat of 100ms. +# - Set debug hook to delay signal by 1 sec while binlog mutex is held. +# - This will cause sender thread wait to timeout for heartbeat and wait +# to get the binlog mutex. +# - When signal is called the sender is not waiting on cond variable so +# the signal is noop, and the binlog mutex is released. +# - The sender thread gets the mutex and exits the wait with the timeout +# code. It sends the heartbeat and needs to check for missed signal +# otherwise it goes to wait again and will be stuck. + +source include/not_group_replication_plugin.inc; +source include/have_debug_sync.inc; +source include/master-slave.inc; +source include/install_semisync.inc; + +# Set heartbeat to a small value. +connection slave; +source include/stop_slave.inc; +let $heartbeat_timeout= query_get_value(select heartbeat_interval from performance_schema.replication_connection_configuration, heartbeat_interval, 1); +change master to master_heartbeat_period = 0.1; +source include/start_slave.inc; + +connection master; +create table t1 (a int); + +# Now simulate 1 sec delay before signal that binlog is updated. +set @@global.debug= '+d,simulate_delay_in_binlog_signal_update'; + +# If binlog sender gets stuck this statement should timeout with warning in errorlog. +insert into t1 values (1); + +# Turn off the delay. +set @@global.debug= '-d,simulate_delay_in_binlog_signal_update'; + +# Run two more statements to restart semisync replication and unblock binlog sender. +insert into t1 values (1); +insert into t1 values (1); + +# +# Clean up +# +source include/uninstall_semisync.inc; + +connection slave; +source include/stop_slave.inc; +disable_query_log; +eval change master to master_heartbeat_period=$heartbeat_timeout; +enable_query_log; +source include/start_slave.inc; + +connection master; +DROP TABLE t1; +source include/sync_slave_sql_with_master.inc; +source include/rpl_end.inc; diff --git a/sql/binlog.cc b/sql/binlog.cc index b003a1f163f..8767b74012a 100644 --- a/sql/binlog.cc +++ b/sql/binlog.cc @@ -3816,6 +3816,7 @@ MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period, bool relay_log) ha_last_updated_binlog_file(0), non_xid_trxs(0), is_relay_log(relay_log), + signal_cnt(0), checksum_alg_reset(binary_log::BINLOG_CHECKSUM_ALG_UNDEF), relay_log_checksum_alg(binary_log::BINLOG_CHECKSUM_ALG_UNDEF), engine_binlog_pos(ULLONG_MAX), diff --git a/sql/binlog.h b/sql/binlog.h index 5bf3e7fe318..fb4103e2fb3 100644 --- a/sql/binlog.h +++ b/sql/binlog.h @@ -483,6 +483,7 @@ class MYSQL_BIN_LOG : public TC_LOG { /* This is relay log */ bool is_relay_log; + ulong signal_cnt; // update of the counter is checked by heartbeat uint8 checksum_alg_reset; // to contain a new value when binlog is rotated /* Holds the last seen in Relay-Log FD's checksum alg value. @@ -943,6 +944,8 @@ class MYSQL_BIN_LOG : public TC_LOG { void set_max_size(ulong max_size_arg); void signal_update() { DBUG_TRACE; + DBUG_EXECUTE_IF("simulate_delay_in_binlog_signal_update", sleep(1);); + signal_cnt++; mysql_cond_broadcast(&update_cond); return; } diff --git a/sql/rpl_binlog_sender.cc b/sql/rpl_binlog_sender.cc index 0910a44d786..bb544220a01 100644 --- a/sql/rpl_binlog_sender.cc +++ b/sql/rpl_binlog_sender.cc @@ -827,6 +827,7 @@ inline int Binlog_sender::wait_with_heartbeat(my_off_t log_pos) { #endif struct timespec ts; int ret; + ulong signal_cnt = mysql_bin_log.signal_cnt; do { set_timespec_nsec(&ts, m_heartbeat_period.count()); @@ -843,7 +844,7 @@ inline int Binlog_sender::wait_with_heartbeat(my_off_t log_pos) { } #endif if (send_heartbeat_event(log_pos, true)) return 1; - } while (!m_thd->killed); + } while (signal_cnt == mysql_bin_log.signal_cnt && !m_thd->killed); return ret ? 1 : 0; }