sync_relay_log 肯定是与relay log相关,所以从rpl_slave.cc处理relay log的代码开始入手
extern "C" void *handle_slave_io(void *arg)
/* XXX: 'synced' should be updated by queue_event to indicate
         whether event has been synced to disk */
      bool synced= 0;
      if (queue_event(mi, event_buf, event_len)) --写event到relay log
      {
        mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
                   ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
                   "could not queue event from master");
        goto err;
      }
      if (RUN_HOOK(binlog_relay_io, after_queue_event,   -- 写成功后的调用,在这个文件中定义的调用方法semisync_slave_plugin.cc
                   (thd, mi, event_buf, event_len, synced)))
      {
        mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
                   ER(ER_SLAVE_FATAL_ERROR),
                   "Failed to run 'after_queue_event' hook");
        goto err;
      }
先看下queue_event
bool queue_event(Master_info* mi,const char* buf, ulong event_len)
....处理了很多的类型
 bool is_error= false;
    /* write the event to the relay log */
    if (likely(rli->relay_log.append_buffer(buf, event_len, mi) == 0))
    {
      mi->set_master_log_pos(mi->get_master_log_pos() + inc_pos);
      DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->get_master_log_pos()));
      rli->relay_log.harvest_bytes_written(rli, true/*need_log_space_lock=true*/);

继续看下append_buffer ,这个函数在binlog.cc这个文件,不是sql_binlog.cc
bool MYSQL_BIN_LOG::append_buffer(const char* buf, uint len, Master_info *mi)
{
  DBUG_ENTER("MYSQL_BIN_LOG::append_buffer");

  // check preconditions
  assert(log_file.type == SEQ_READ_APPEND);
  assert(is_relay_log);
  mysql_mutex_assert_owner(&LOCK_log);

  // write data
  bool error= false;
  if (my_b_append(&log_file,(uchar*) buf,len) == 0)
  {
    bytes_written += len;
    error= after_append_to_relay_log(mi);
  }
  else
    error= true;

  DBUG_RETURN(error);
}
继续看my_b_append
/*
  Append a block to the write buffer.
  This is done with the buffer locked to ensure that we don't read from
  the write buffer before we are ready with it.
*/

int my_b_append(IO_CACHE *info, const uchar *Buffer, size_t Count)
lock_append_buffer(info);
  rest_length= (size_t) (info->write_end - info->write_pos);
  if (Count <= rest_length)
    goto end;
  memcpy(info->write_pos, Buffer, rest_length);
  Buffer+=rest_length;
  Count-=rest_length;
  info->write_pos+=rest_length;
  if (my_b_flush_io_cache(info,0))
  {
    unlock_append_buffer(info);
    return 1;
  }
  if (Count >= IO_SIZE)
  {					/* Fill first intern buffer */
    length=Count & (size_t) ~(IO_SIZE-1);
    if (mysql_file_write(info->file,Buffer, length, info->myflags | MY_NABP))
    {
      unlock_append_buffer(info);
      return info->error= -1;
    }
    Count-=length;
    Buffer+=length;
    info->end_of_file+=length;
  }

end:
  memcpy(info->write_pos,Buffer,(size_t) Count);
  info->write_pos+=Count;
  unlock_append_buffer(info);
  return 0;
查看my_b_flush_io_cache, 刷到文件
int my_b_flush_io_cache(IO_CACHE *info,
                        int need_append_buffer_lock MY_ATTRIBUTE((unused)))
{
  size_t length;
  my_off_t pos_in_file;
  my_bool append_cache= (info->type == SEQ_READ_APPEND);
  DBUG_ENTER("my_b_flush_io_cache");
  DBUG_PRINT("enter", ("cache: 0x%lx", (long) info));

  DBUG_EXECUTE_IF("simulate_error_during_flush_cache_to_file",
                  {
                    DBUG_RETURN(TRUE);
                  });
  if (!append_cache)
    need_append_buffer_lock= 0;

  if (info->type == WRITE_CACHE || append_cache)
  {
    if (info->file == -1)
    {
      if (real_open_cached_file(info))
	DBUG_RETURN((info->error= -1));
    }
    LOCK_APPEND_BUFFER;

    if ((length=(size_t) (info->write_pos - info->write_buffer)))
    {
      /*
        In case of a shared I/O cache with a writer we do direct write
        cache to read cache copy. Do it before the write here so that
        the readers can work in parallel with the write.
        copy_to_read_buffer() relies on info->pos_in_file.
      */
      if (info->share)
        copy_to_read_buffer(info, info->write_buffer, length);

      pos_in_file=info->pos_in_file;
      /*
	If we have append cache, we always open the file with
	O_APPEND which moves the pos to EOF automatically on every write
      */
      if (!append_cache && info->seek_not_done)
      {					/* File touched, do seek */
	if (mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(0)) ==
	    MY_FILEPOS_ERROR)
	{
	  UNLOCK_APPEND_BUFFER;
	  DBUG_RETURN((info->error= -1));
	}
	if (!append_cache)
	  info->seek_not_done=0;
      }
      if (!append_cache)
	info->pos_in_file+=length;
      info->write_end= (info->write_buffer+info->buffer_length-
			((pos_in_file+length) & (IO_SIZE-1)));

      if (mysql_file_write(info->file,info->write_buffer,length,
		   info->myflags | MY_NABP))
	info->error= -1;
      else
	info->error= 0;
      if (!append_cache)
      {
        set_if_bigger(info->end_of_file,(pos_in_file+length));
      }
      else
      {
	info->end_of_file+=(info->write_pos-info->append_read_pos);
	assert(info->end_of_file == mysql_file_tell(info->file, MYF(0)));
      }

      info->append_read_pos=info->write_pos=info->write_buffer;
      ++info->disk_writes;
      UNLOCK_APPEND_BUFFER;
      DBUG_RETURN(info->error);
    }
  }
  UNLOCK_APPEND_BUFFER;
  DBUG_RETURN(0);
}

写入到文件后,执行bool MYSQL_BIN_LOG::after_append_to_relay_log(Master_info *mi)进行flush和sync

// Flush and sync
  bool error= false;
  if (flush_and_sync(0) == 0 && can_rotate)
  {
    /*
      If the last event of the transaction has been flushed, we can add
      the GTID (if it is not empty) to the logged set, or else it will
      not be available in the Previous GTIDs of the next relay log file
      if we are going to rotate the relay log.
    */
    Gtid *last_gtid_queued= mi->get_last_gtid_queued();
    if (!last_gtid_queued->is_empty())
    {
      global_sid_lock->rdlock();
      mi->rli->add_logged_gtid(last_gtid_queued->sidno,
                               last_gtid_queued->gno);
      global_sid_lock->unlock();
      mi->clear_last_gtid_queued();
    }

    /*
      If relay log is too big, rotate. But only if not in the middle of a
      transaction when GTIDs are enabled.
      We now try to mimic the following master binlog behavior: "A transaction
      is written in one chunk to the binary log, so it is never split between
      several binary logs. Therefore, if you have big transactions, you might
      see binary log files larger than max_binlog_size."
    */
    if ((uint) my_b_append_tell(&log_file) >
        DBUG_EVALUATE_IF("rotate_slave_debug_group", 500, max_size))
    {
      error= new_file_without_locking(mi->get_mi_description_event());
    }
  }

  signal_update();

     我们继续看成功后的调用
     semisync_slave_plugin.cc这个文件中定义了回调函数
     Binlog_relay_IO_observer relay_io_observer = {
  sizeof(Binlog_relay_IO_observer), // len

  repl_semi_slave_io_start,	// start
  repl_semi_slave_io_end,	// stop
  repl_semi_slave_sql_start,    // start sql thread
  repl_semi_slave_sql_stop,     // stop sql thread
  repl_semi_slave_request_dump,	// request_transmit
  repl_semi_slave_read_event,	// after_read_event
  repl_semi_slave_queue_event,	// after_queue_event --这个
  repl_semi_reset_slave,	// reset
};
通过semi_sync_need_reply 来判断是否需要slave的回复
int repl_semi_slave_queue_event(Binlog_relay_IO_param *param,
				const char *event_buf,
				unsigned long event_len,
				uint32 flags)
{
  if (rpl_semi_sync_slave_status && semi_sync_need_reply)
  {
    /*
      We deliberately ignore the error in slaveReply, such error
      should not cause the slave IO thread to stop, and the error
      messages are already reported.
    */
    (void) repl_semisync.slaveReply(param->mysql,
                                    param->master_log_name,
                                    param->master_log_pos);
  }
  return 0;
}

/*
  indicate whether or not the slave should send a reply to the master.
  This is set to true in repl_semi_slave_read_event if the current
  event read is the last event of a transaction. And the value is
  checked in repl_semi_slave_queue_event.
*/
bool semi_sync_need_reply= false;

这个参数在repl_semi_slave_read_event这个文件中设置的true
int repl_semi_slave_read_event(Binlog_relay_IO_param *param,
			       const char *packet, unsigned long len,
			       const char **event_buf, unsigned long *event_len)
{
  if (rpl_semi_sync_slave_status)
    return repl_semisync.slaveReadSyncHeader(packet, len,
					     &semi_sync_need_reply,
					     event_buf, event_len);
  *event_buf= packet;
  *event_len= len;
  return 0;
}

继续看
int ReplSemiSyncSlave::slaveReadSyncHeader(const char *header,
                                      unsigned long total_len,
                                      bool  *need_reply,
                                      const char **payload,
                                      unsigned long *payload_len)
{
  const char *kWho = "ReplSemiSyncSlave::slaveReadSyncHeader";
  int read_res = 0;
  function_enter(kWho);

  if ((unsigned char)(header[0]) == kPacketMagicNum)
  {
    *need_reply  = (header[1] & kPacketFlagSync); -- 设置的是否需要replay
    *payload_len = total_len - 2;
    *payload     = header + 2;

    if (trace_level_ & kTraceDetail)
      sql_print_information("%s: reply - %d", kWho, *need_reply);
  }
  else
  {
    sql_print_error("Missing magic number for semi-sync packet, packet "
                    "len: %lu", total_len);
    read_res = -1;
  }