Master Thread是非常核心的后台线程,具有最高的线程优先级,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括:脏页的刷新;合并插入缓冲;undo页的回收等。
srv0srv.cc-->srv_master_thread
一、主循环loop
1、srv_master_sleep
睡眠1秒
2、srv_master_do_active_tasks
服务器非空闲时的操作
2.1 log_free_check
确保重做日志文件中有足够的可重用空间:如果不够,就刷新日志缓冲区或创建新的检查点
2.2 ibuf_merge_in_background
合并 5%*srv_io_capacity 大小的 insert buffer,
srv_io_capacity表示磁盘IO的吞吐量,默认值是200,可以根据磁盘的性能做调整
2.2.1调用ibuf_merge_in_background(bool full)
默认为5%,如果缓冲池使用超过一半,则加上超过一半的部分所占的比例
2.3刷新一次重做日志缓冲至磁盘
2.3.1如果current_time - srv_last_log_flush_time)>= srv_flush_log_at_timeout则调用log_buffer_sync_in_background刷新日志至磁盘。
由于每次循环默认睡1s,srv_flush_log_at_timeout=1,所以该次日志刷新为必做操作
2.4每间隔47秒执行一次 LRU 缓存清理检查,通过逐出未使用的表,在LRU缓存中腾出空间,最大扫描表长为百分之50
2.4.1 srv_master_evict_from_table_cache
逐出未使用的表
……|-->需要持有dict_operation_lock的x锁,以及dict_sys->mutex
……|--> dict_make_room_in_cache
…………|-->如果dict_sys->table_LRU(可以从缓存中收回的表的链表)的长度小于table_def_size,不检查直接返回
…………|-->否则从LRU尾部开始对于可以驱逐的表从dict cache中驱逐,直到table_LRU为空,或者检查长度>50%,或者dict cache长度<=table_def_size停止扫描
………………|-->dict_table_can_be_evicted
table可以被驱逐的情况:
(1)该表当前没有被任何事务引用
(2)该表没有加锁
(3)该表的索引没有被adaptive hash index引用
………………|-->dict_table_remove_from_cache_low
从dict cache移除表
2.5每间隔7秒执行一次设置新的 checkpoint,只向 log file 中写入 LSN,不做脏页刷新
3、 srv_master_do_idle_tasks
服务器空闲时的操作
3.1确保重做日志文件中有足够的可重用空间:如果不够,就刷新日志缓冲区或创建新的检查点
3.2(区别于非空闲时)合并 100%*srv_io_capacity 大小的 insert buffer
3.2.1调用ibuf_merge_in_background(bool full)
3.3(区别于非空闲时)执行LRU缓存清理,扫描100%
3.4刷新一次重做日志缓冲至磁盘
3.5设置新的checkpoint,只向log file中写入LSN,不做脏页刷新
二、暂停线程
1、当srv_force_recovery >= 2时进入暂停线程。
srv_force_recovery默认为0,非0时会跳过崩恢复流程中的表空间校验过程,且非0时,不允许用户对数据进行任何修改。
1.1 srv_force_recovery可选值与影响,大的数字包含前面所有数字的影响。
-如果你能以3或更低值恢复/转储你的表时,这种情况库还相对安全的,因为只在相对独立的页上的一些数据会丢失。
-大于等于4时,数据库损坏度比较大危险,因为数据文性被永久地损坏。
-值6被认为是严重的,数据库页被留在一个陈旧的状态,这反过来又可能带给B-trees和其它数据库结构更多的损坏。
-作为一个安全措施,InnoDB 在该值大于0时阻止INSERT,UPDATE或DELETE操作。设为4或更高时,InnoDB库处于只读模式。
1:即使检查到损坏的页也让服务器继续运行
2:阻止主线程的运行,如主线程在清除过程中发生崩溃则会阻止
3:在recovery后不执行事务回滚操作
4:不执行插入缓冲的合并操作
5:启动数据库时不查看undo日志,InnoDB存储引擎会将未提交的事务视为已提交
6:recovery时不执行日志前滚操作