Mysql主从复制-SQL线程函数-handle_slave_sql源码整理
一、整体逻辑
首先创建多个worker线程等待event,然后读取event传入到队列中,worker从队列中取出event后再apply event。
1.SQL线程启动
MySQL从库在执行start slave命令时,在MySQL内部依次调用下面的函数来启动IO线程和SQL线程。
- mysql_execute_command(),sql/sql_parse.cc
- start_slave_cmd(),sql/rpl_slave.cc
- start_slave(),sql/rpl_slave.cc
- start_slave_threads(),sql/rpl_slave.cc
- start_slave_thread(),sql/rpl_slave.cc
start_slave_threads 函数在另外一个地方也会被调用,init_slave()函数,这个函数是在MySQL启动时调用,如果没有指定skip-slave-start,主从复制随着MySQL启动而自动启动。
2.SQL线程函数
MySQL主从复制SQL线程的线程函数位于sql/rpl_slave.cc文件中,定义如下:
extern “C” void *handle_slave_sql(void *arg)
(1).创建工作线程
在MySQL 5.7 版本,开启逻辑并行复制,SQL线程会创建多个工作线程并发进行relay log日志的应用,源码中创建工作线程的调用栈如下:
- handle_slave_sql()
- slave_start_workers()
- slave_start_single_worker()
- mysql_thread_create()
(2).进入循环
SQL线程创建完工作线程之后,会进入while循环,直到停止复制或者SQL线程被kill。
在循环中的主要函数调用关系如下:
- handle_slave_sql(),SQL线程主函数
- exec_relay_log_event()
- apply_event_and_update_pos()
- ev->apply_event(rli);
- ev->do_apply_event()
exec_relay_log_event 函数读取relay log中的event。
apply_event_and_update_pos函数去应用relay log event。在这个函数里,会将thd的server_id设置成event的server_id,保证event被应用后,生成自己的binlog时,server_id仍然是原始值。
apply_event_and_update_pos函数中会调用函数sql_delay_event(),用于处理延迟复制,比如使用了CHANGE MASTER TO MASTER_DELAY = X 这样的语法。
ev->apply_event()函数是event自己成员函数,这个函数里面会去判断event是否可以并行应用,如果不可以,就在当前线程(SQL线程)去处理这个event,如果可以并行应用,则会返回上一层函数apply_event_and_update_pos,将event丢进入一个队列,后续worker线程会去这个队列中取出event处理。
(3).工作线程主要逻辑
工作线程的线程函数为:
extern “C” void *handle_slave_worker(void *arg)
主要调用关系如下:
- handle_slave_worker(),工作线程主函数
- slave_worker_exec_job_group()
- slave_worker_exec_event()
- ev->do_apply_event_worker(this);
- ev->do_apply_event()
- mysql_parse()
工作线程内部主要是一个while循环,调用slave_worker_exec_job_group()函数执行分配给自己的任务。
在slave_worker_exec_job_group函数中,拿到event后,调用下面这个函数应用event:
error= worker->slave_worker_exec_event(ev);
在slave_worker_exec_event函数中又会调用event自己的成员函数来应用event:
ret= ev->do_apply_event_worker(this);
在do_apply_event_worker函数中,调用不同类型event的do_apply_event()成员函数。比如Query_log_event这种类型的event。
Query_log_event::do_apply_event()
do_apply_event函数中最终调用mysql_parse函数执行SQL语句。