从 time_diff 的计算方式来看,可以发现这个延迟基本上就是一个时间差值,然后再算上主从之间的时间差。不过 if 挺多的,所以借用源代码文件中的注释:
/*
The pseudo code to compute Seconds_Behind_Master:
if (SQL thread is running)
{
if (SQL thread processed all the available relay log)
{
if (IO thread is running)
print 0;
else
print NULL;
}
else
compute Seconds_Behind_Master;
}
else
print NULL;
*/
./sql/rpl_slave.cc
......
if (ev)
{
enum enum_slave_apply_event_and_update_pos_retval exec_res;
ptr_ev= &ev;
/*
Even if we don't execute this event, we keep the master timestamp,
so that seconds behind master shows correct delta (there are events
that are not replayed, so we keep falling behind).
If it is an artificial event, or a relay log event (IO thread generated
event) or ev->when is set to 0, or a FD from master, or a heartbeat
event with server_id '0' then we don't update the last_master_timestamp.
In case of parallel execution last_master_timestamp is only updated when
a job is taken out of GAQ. Thus when last_master_timestamp is 0 (which
indicates that GAQ is empty, all slave workers are waiting for events from
the Coordinator), we need to initialize it with a timestamp from the first
event to be executed in parallel.
*/
if ((!rli->is_parallel_exec() || rli->last_master_timestamp == 0) &&
!(ev->is_artificial_event() || ev->is_relay_log_event() ||
(ev->common_header->when.tv_sec == 0) ||
ev->get_type_code() == binary_log::FORMAT_DESCRIPTION_EVENT ||
ev->server_id == 0))
{
rli->last_master_timestamp= ev->common_header->when.tv_sec +
(time_t) ev->exec_time;
DBUG_ASSERT(rli->last_master_timestamp >= 0);
}
......
./sql/rpl\_slave.cc
......
/*
We need to ensure that this is never called at this point when
cnt is zero. This value means that the checkpoint information
will be completely reset.
*/
/*
Update the rli->last_master_timestamp for reporting correct Seconds_behind_master.
If GAQ is empty, set it to zero.
Else, update it with the timestamp of the first job of the Slave_job_queue
which was assigned in the Log_event::get_slave_worker() function.
*/
ts= rli->gaq->empty()
? 0
: reinterpret_cast<Slave_job_group*>(rli->gaq->head_queue())->ts;
rli->reset_notified_checkpoint(cnt, ts, need_data_lock, true);
/* end-of "Coordinator::"commit_positions" */
......
/*
Currently, the checkpoint routine is being called by the SQL Thread.
For that reason, this function is called call from appropriate points
in the SQL Thread's execution path and the elapsed time is calculated
here to check if it is time to execute it.
*/
set_timespec_nsec(&curr_clock, 0);
ulonglong diff= diff_timespec(&curr_clock, &rli->last_clock);
if (!force && diff < period)
{
/*
We do not need to execute the checkpoint now because
the time elapsed is not enough.
*/
DBUG_RETURN(FALSE);
}