@@ -808,8 +808,10 @@ static ulonglong get_heartbeat_period(THD * thd)
808808 @param packet buffer to store the heartbeat instance
809809 @param event_coordinates binlog file name and position of the last
810810 real event master sent from binlog
811+ @param send_timestamp flag enables sending the HB event with
812+ the current timestamp: time().
811813
812- @note
814+ @note
813815 Among three essential pieces of heartbeat data Log_event::when
814816 is computed locally.
815817 The error to send is serious and should force terminating
@@ -818,17 +820,22 @@ static ulonglong get_heartbeat_period(THD * thd)
818820static int send_heartbeat_event (NET* net, String* packet,
819821 const struct event_coordinates *coord,
820822 bool is_semi_sync_slave,
821- uint8 checksum_alg_arg)
823+ uint8 checksum_alg_arg,
824+ bool send_timestamp)
822825{
823826 DBUG_ENTER (" send_heartbeat_event" );
824827 char header[LOG_EVENT_HEADER_LEN];
825828 my_bool do_checksum= checksum_alg_arg != BINLOG_CHECKSUM_ALG_OFF &&
826829 checksum_alg_arg != BINLOG_CHECKSUM_ALG_UNDEF;
827830
828- // NOTE: if @last_master_timestamp is provided we're a slave and we use this
829- // value in the HB event otherwise we use now()
830- time_t ts= mysql_bin_log.last_master_timestamp .load ();
831- if (!ts) ts= time (0 );
831+ time_t ts= 0 ;
832+
833+ if (send_timestamp) {
834+ // NOTE: if @last_master_timestamp is provided we're a slave and we use this
835+ // value in the HB event otherwise we use now()
836+ ts= mysql_bin_log.last_master_timestamp .load ();
837+ if (!ts) ts= time (0 );
838+ }
832839 memcpy (header, &ts, 4 );
833840
834841 header[EVENT_TYPE_OFFSET] = HEARTBEAT_LOG_EVENT;
@@ -880,6 +887,15 @@ static int send_heartbeat_event(NET* net, String* packet,
880887 later. Note that, the caller has to send the last skipped coordinates
881888 to this function.
882889
890+ Note that this function will not send HeartBeat events that carry the current
891+ timestamp. This this because this function is ONLY used to send HB update
892+ when the previous transaction has been skipped. Note that HB events'
893+ timestamps will be used by the slave to calculate the seconds behind master.
894+
895+ The only place that makes sense for the event to carry a timestamp is when
896+ the master is waiting on the update and keeping sending HB events to keep
897+ the connection.
898+
883899 @param[in] net This master-slave network handler
884900 @param[in] packet packet that is to be sent to the slave.
885901 @param[in] last_skip_coord coordinates for last skipped transaction
@@ -904,17 +920,24 @@ static int send_last_skip_group_heartbeat(THD *thd, NET* net, String *packet,
904920 String save_packet;
905921 int save_offset= *ev_offset;
906922
907- /* Save the current read packet */
923+ /* Save the current read packet */
908924 save_packet.swap (*packet);
909925
910926 if (reset_transmit_packet (thd, 0 , ev_offset, errmsg, observe_transmission,
911927 packet, packet_buffer, packet_buffer_size,
912928 semi_sync_slave))
913929 DBUG_RETURN (-1 );
914930
915- /* Send heart beat event to the slave to update slave threads coordinates */
916- if (send_heartbeat_event (net, packet, last_skip_coord,
917- semi_sync_slave, checksum_alg_arg))
931+ /* *
932+ * Send heart beat event to the slave to update slave threads coordinates
933+ * Note that we will not send timestamp in these heart beat events
934+ */
935+ if (send_heartbeat_event (net,
936+ packet,
937+ last_skip_coord,
938+ semi_sync_slave,
939+ checksum_alg_arg,
940+ false ))
918941 {
919942 *errmsg= " Failed on my_net_write()" ;
920943 my_errno= ER_UNKNOWN_ERROR;
@@ -1922,6 +1945,10 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
19221945 // Both diff_timespec() and heartbeat_period are in nano seconds.
19231946 time_for_hb_event= (diff_timespec (cur_clock, last_event_sent_ts) >=
19241947 heartbeat_period);
1948+ DBUG_EXECUTE_IF (" send_zero_hb_event" ,
1949+ {
1950+ time_for_hb_event= true ;
1951+ });
19251952 }
19261953
19271954 if ((!skip_group && last_skip_group
@@ -1938,6 +1965,10 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
19381965 is the first event to be sent to the slave. In this case, it is
19391966 no need to send a HB event (which might have coordinates
19401967 of previous binlog file).
1968+
1969+ This heartbeat event sending only happens when the master is in the
1970+ middle or has just completed skipping all the trxs. Therefore, HB
1971+ shouldn't carry Timestamp.
19411972 */
19421973
19431974 if (send_last_skip_group_heartbeat (thd, net, packet, p_last_skip_coord,
@@ -2210,6 +2241,10 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
22102241 If the heartbeat is on, it is better to send a heartbeat
22112242 event as the time_out of certain functions (Ex: master_pos_wait()
22122243 or semi sync ack timeout) might be less than heartbeat period.
2244+
2245+ This can happen when the slave has exact same GTID as the master.
2246+ In this case, we still send the first HB with 0 timestamp to be
2247+ safe since the follow up HB with carry the right timestamp
22132248 */
22142249 if (skip_group)
22152250 {
@@ -2254,8 +2289,19 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
22542289 thd->EXIT_COND (&old_stage);
22552290 GOTO_ERR;
22562291 }
2257- if (send_heartbeat_event (net, packet, p_coord,
2258- semi_sync_slave, current_checksum_alg))
2292+ /* *
2293+ * HB events sent here are essentially when the master is waiting
2294+ * on updates and send HB to keep the connection connected.
2295+ *
2296+ * This is the only place that sending HB with Timestamp makes
2297+ * sense and won't break monotonic TS calculated SBM
2298+ */
2299+ if (send_heartbeat_event (net,
2300+ packet,
2301+ p_coord,
2302+ semi_sync_slave,
2303+ current_checksum_alg,
2304+ true ))
22592305 {
22602306 errmsg = " Failed on my_net_write()" ;
22612307 my_errno= ER_UNKNOWN_ERROR;
@@ -2357,7 +2403,11 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
23572403
23582404 if (!skip_group && !goto_next_binlog)
23592405 {
2360- /* If the last group was skipped, send a HB event */
2406+ /* *
2407+ * If the last group was skipped, send a HB event,
2408+ * similarly, HB sent here should not carry TS since the last
2409+ * trx is skipped and we are not sure if we are waiting on update
2410+ */
23612411 if (last_skip_group &&
23622412 send_last_skip_group_heartbeat (thd, net, packet,
23632413 p_last_skip_coord, &ev_offset,
0 commit comments