开源数据库 - mysql - innodb源码阅读 - master线程(一)
master struct
/** The master thread controlling the server. */
void srv_master_thread() {
DBUG_TRACE;
srv_slot_t *slot; // 槽位
THD *thd = create_internal_thd(); // 创建内部线程
ut_ad(!srv_read_only_mode); //断言 srv_read_only_mode 为 false
srv_main_thread_process_no = os_proc_get_number(); // 进程号
srv_main_thread_id = std::this_thread::get_id(); // 线程号
slot = srv_reserve_slot(SRV_MASTER); // 保留槽位
ut_a(slot == srv_sys->sys_threads); // 断言 srv_sys->sys_threads 为 slot
srv_master_main_loop(slot); // 主循环
srv_master_pre_dd_shutdown_loop(); // 执行 pre_dd_shutdown 任务
os_event_set(srv_threads.m_master_ready_for_dd_shutdown); // 设置事件
/* This is just for test scenarios. */
srv_thread_delay_cleanup_if_needed(true); // 延迟清理线程
while (srv_shutdown_state.load() < SRV_SHUTDOWN_MASTER_STOP) { // 等待srv_shutdown_state 为 SRV_SHUTDOWN_MASTER_STOP
srv_master_wait(slot); // 等待事件
}
srv_master_shutdown_loop(); // 执行 shutdown 任务
srv_main_thread_op_info = "exiting"; // 操作信息
destroy_internal_thd(thd); // 销毁内部线程
}
当前代码是InnoDB存储引擎中主(master)线程的实现部分。主线程负责控制和管理整个InnoDB存储引擎的运行。以下是对代码的详细解释:
-
函数声明和初始化:
void srv_master_thread() { DBUG_TRACE; srv_slot_t *slot; THD *thd = create_internal_thd(); ut_ad(!srv_read_only_mode); srv_main_thread_process_no = os_proc_get_number(); srv_main_thread_id = std::this_thread::get_id(); slot = srv_reserve_slot(SRV_MASTER); ut_a(slot == srv_sys->sys_threads);
DBUG_TRACE
:这是一个调试宏,用于在调试模式下输出跟踪信息。create_internal_thd()
:创建一个内部线程句柄(THD)。ut_ad(!srv_read_only_mode)
:断言服务器不是只读模式。srv_main_thread_process_no
和srv_main_thread_id
:获取并设置主线程的进程号和线程ID。srv_reserve_slot(SRV_MASTER)
:为主线程保留一个槽位(slot)。ut_a(slot == srv_sys->sys_threads)
:断言保留的槽位是系统线程。
-
主循环:
srv_master_main_loop(slot); srv_master_pre_dd_shutdown_loop(); os_event_set(srv_threads.m_master_ready_for_dd_shutdown); srv_thread_delay_cleanup_if_needed(true); while (srv_shutdown_state.load() < SRV_SHUTDOWN_MASTER_STOP) { srv_master_wait(slot); } srv_master_shutdown_loop();
srv_master_main_loop(slot)
:执行主循环,处理各种任务和检查点。srv_master_pre_dd_shutdown_loop()
:在DD(数据字典)操作前执行关闭任务。os_event_set(srv_threads.m_master_ready_for_dd_shutdown)
:设置事件,表示主线程准备好进行DD操作。srv_thread_delay_cleanup_if_needed(true)
:延迟清理线程,如果需要的话。while (srv_shutdown_state.load() < SRV_SHUTDOWN_MASTER_STOP)... srv_master_wait(slot)
:等待直到关闭状态达到SRV_SHUTDOWN_MASTER_STOP
。srv_master_shutdown_loop()
:执行关闭循环,处理最后的关闭任务。
-
线程清理:
srv_main_thread_op_info = "exiting"; destroy_internal_thd(thd); }
srv_main_thread_op_info = "exiting"
:设置主线程操作信息为“exiting”。destroy_internal_thd(thd)
:销毁内部线程句柄,释放资源。
总结来说,这段代码实现了InnoDB存储引擎的主线程,负责管理和控制整个存储引擎的运行,包括处理任务、执行检查点、关闭操作等。
master main_loop
/** Executes the main loop of the master thread.
@param[in] slot slot reserved as SRV_MASTER */
static void srv_master_main_loop(srv_slot_t *slot) {
if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) {
/* When innodb_force_recovery is at least SRV_FORCE_NO_BACKGROUND,
we avoid performing active/idle master's tasks. However, we still
need to ensure that:
srv_shutdown_state >= SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS,
after we exited srv_master_main_loop(). Keep waiting until that
is satisfied and then exit. */
while (srv_shutdown_state.load() <
SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS) {
srv_master_wait(slot);
}
return;
}
ulint old_activity_count = srv_get_activity_count();
while (srv_shutdown_state.load() <
SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS) {
srv_master_sleep();
MONITOR_INC(MONITOR_MASTER_THREAD_SLEEP);
/* Just in case - if there is not much free space in redo,
try to avoid asking for troubles because of extra work
performed in such background thread. */
srv_main_thread_op_info = "checking free log space";
log_free_check();
if (srv_check_activity(old_activity_count)) {
old_activity_count = srv_get_activity_count();
srv_master_do_active_tasks();
} else {
srv_master_do_idle_tasks();
}
/* Purge any deleted tablespace pages. */
fil_purge();
}
}
这段代码定义了一个名为 srv_master_main_loop
的静态函数,它是 InnoDB 存储引擎中主循环的一部分。这个函数在主线程中执行,负责处理各种任务,包括检查和处理活动、执行空闲任务、检查日志空间以及清理删除的表空间页面。
函数的参数是一个指向 srv_slot_t
类型的指针 slot
,这个指针指向一个预留的槽位,通常用于线程间的通信。
函数的逻辑如下:
-
首先,函数检查
srv_force_recovery
变量的值。如果这个值大于等于SRV_FORCE_NO_BACKGROUND
,则表示 InnoDB 处于强制恢复模式,此时主循环不会执行任何后台任务。相反,它会等待srv_shutdown_state
变量的值达到SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS
,然后退出循环。 -
如果没有处于强制恢复模式,函数会进入一个无限循环,直到
srv_shutdown_state
变量的值达到SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS
。 -
在循环内部,函数首先调用
srv_master_sleep
函数,让主线程休眠 1 秒。 -
然后,函数增加
MONITOR_MASTER_THREAD_SLEEP
监控计数器的值,表示主线程已经休眠。 -
接着,函数检查日志空间的可用情况,如果可用空间不足,它会尝试避免执行额外的工作,以防止出现问题。
-
之后,函数检查活动计数,如果活动计数发生变化,它会调用
srv_master_do_active_tasks
函数执行活跃任务;如果活动计数没有变化,它会调用srv_master_do_idle_tasks
函数执行空闲任务。 -
最后,函数调用
fil_purge
函数,清理删除的表空间页面。
总的来说,这个函数负责管理主线程的活动,确保在适当的时候执行必要的任务,同时避免在不必要的时候执行过多的工作,以保持系统的稳定性和性能。
srv_master_main_loop
的静态函数,它是 InnoDB 存储引擎中主(master)线程的主要循环。这个函数负责处理服务器的各种活动,包括检查点、日志管理、线程调度等。以下是对代码的详细解释:
-
函数声明和参数:
static void srv_master_main_loop(srv_slot_t *slot) {
srv_slot_t *slot
:这是一个指向srv_slot_t
类型的指针,用于标识线程的槽位。
-
强制恢复级别检查:
if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) { /* When innodb_force_recovery is at least SRV_FORCE_NO_BACKGROUND, we avoid performing active/idle master's tasks. However, we still need to ensure that: srv_shutdown_state >= SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS, after we exited srv_master_main_loop(). Keep waiting until that is satisfied and then exit. */ while (srv_shutdown_state.load() < SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS) { srv_master_wait(slot); } return; }
- 这段代码检查
srv_force_recovery
的值,如果它大于等于SRV_FORCE_NO_BACKGROUND
,则主循环会等待直到srv_shutdown_state
大于等于SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS
,然后退出循环。
- 这段代码检查
-
主循环:
ulint old_activity_count = srv_get_activity_count(); while (srv_shutdown_state.load() < SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS) { srv_master_sleep(); MONITOR_INC(MONITOR_MASTER_THREAD_SLEEP); /* Just in case - if there is not much free space in redo, try to avoid asking for troubles because of extra work performed in such background thread. */ srv_main_thread_op_info = "checking free log space"; log_free_check(); if (srv_check_activity(old_activity_count)) { old_activity_count = srv_get_activity_count(); srv_master_do_active_tasks(); } else { srv_master_do_idle_tasks(); } /* Purge any deleted tablespace pages. */ fil_purge(); }
ulint old_activity_count = srv_get_activity_count();
:获取当前的活动计数。while (srv_shutdown_state.load() < SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS) {...}
:主循环会一直运行,直到srv_shutdown_state
大于等于SRV_SHUTDOWN_PRE_DD_AND_SYSTEM_TRANSACTIONS
。srv_master_sleep();
:主线程睡眠 1 秒。MONITOR_INC(MONITOR_MASTER_THREAD_SLEEP);
:增加监控器中主线程睡眠的计数。srv_main_thread_op_info = "checking free log space";
:设置主线程的操作信息为“检查空闲日志空间”。log_free_check();
:检查日志文件的空闲空间。if (srv_check_activity(old_activity_count)) {...}
:检查活动计数是否有变化,如果有,则执行srv_master_do_active_tasks()
;否则,执行srv_master_do_idle_tasks()
。fil_purge();
:清除任何已删除的表空间页面。
总结来说,这段代码实现了 InnoDB 存储引擎的主循环,负责管理和控制整个存储引擎的运行,包括处理任务、执行检查点、关闭操作等。
通过 srv_master_main_loop
函数,InnoDB 可以实现对线程的精细控制和管理。
InnoDB 的 master 线程主循环主要负责管理和维护数据库的运行状态。具体来说,它执行以下任务:
-
检查和处理活动:master 线程会定期检查数据库的活动情况,包括事务的提交、回滚、锁的释放等。如果发现有需要处理的活动,它会调用相应的函数进行处理。
-
执行空闲任务:如果没有紧急的活动需要处理,master 线程会执行一些空闲任务,例如清理过期的日志、检查和优化索引等。
-
检查日志空间:master 线程会定期检查日志文件的可用空间,如果空间不足,它会采取措施释放空间,例如进行日志切换或删除旧的日志文件。
-
清理删除的表空间页面:当表空间中的页面被标记为删除时,master 线程会调用
fil_purge
函数来清理这些页面,释放存储空间。 -
等待和处理事件:在某些情况下,master 线程可能需要等待特定的事件发生,例如等待其他线程完成某些任务。一旦事件发生,它会相应地处理这些事件。
-
执行关闭前的准备工作:当数据库需要关闭时,master 线程会执行一系列的准备工作,例如等待所有事务完成、将脏页刷新到磁盘、关闭所有打开的文件和连接等。
-
执行关闭任务:在关闭过程中,master 线程会执行一些特定的关闭任务,例如清理资源、更新元数据等。
-
监控和报告状态:master 线程会监控数据库的运行状态,并通过一些监控计数器和状态信息来报告当前的运行情况。
总的来说,master 线程主循环是 InnoDB 存储引擎的核心部分,它确保数据库能够稳定、高效地运行,并在需要时正确地处理各种任务和事件。
扩展
线程与槽位
线程和槽在计算机编程和操作系统领域中各自扮演着重要的角色,并且它们之间存在一定的关联,特别是在某些特定的框架或系统中(如Qt或Suricata)。以下是对线程和槽的详细解释:
线程
-
定义:线程是操作系统能够进行运算调度的最小单位,被包含在进程之中,是进程中的实际运作单位。每个线程都拥有一个执行的指令序列,该序列决定了线程的功能。
-
作用:
- 提高系统效率:通过并发执行多个线程,可以更充分地利用多核处理器,提高系统的整体效率。
- 简化编程模型:线程提供了一种比进程更轻量级的并发执行方式,使得程序员可以更容易地编写并发程序。
- 资源共享:线程共享其所属进程的地址空间和资源,这有助于减少资源开销和简化资源管理。
槽(Slot)
-
定义:槽在不同的上下文中可能有不同的含义。在编程中,槽通常指的是一种机制或数据结构,用于存储和调用特定的函数或方法。特别是在某些事件驱动或信号槽机制的框架中(如Qt),槽是指与信号相关联的函数或方法,当信号被触发时,槽函数会被调用执行。
-
在特定系统中的作用(以Suricata为例):
- 模块管理:在Suricata中,槽(Slot)用于管理不同的模块。每个线程都包含一个槽的链表,每个槽结点都悬挂着不同的模块。程序执行时会遍历槽链表,按照加入链表的顺序执行模块。
- 函数指针:槽中包含了函数指针,用于指向模块的各种处理函数,如初始化函数、数据包获取函数、退出打印函数等。这使得系统能够灵活地调用不同的模块处理函数,实现特定的功能。
线程与槽的关联
- 事件驱动:在事件驱动的编程模型中,线程和槽紧密配合工作。线程负责监听和处理事件,而槽则作为事件处理函数的存储和调用机制。当事件发生时,线程会触发相应的槽函数来处理该事件。
- 信号槽机制:在某些框架中(如Qt),线程和槽通过信号槽机制进行通信。信号由某个线程发出,而槽函数则可以在不同的线程中被调用执行。这实现了线程间的解耦和异步通信。
综上所述,线程和槽在编程和操作系统中各自发挥着重要的作用。线程提供了并发执行的能力,而槽则提供了一种灵活的事件处理机制。它们之间的关联使得系统能够更高效地处理并发事件和任务。
srv_slot_t *slot;
这个变量在 InnoDB 存储引擎中用于管理线程的槽位(slot)。在 InnoDB 中,每个线程都需要一个槽位来存储其状态和相关信息。这个槽位是通过 srv_reserve_slot
函数分配的,并且在线程的生命周期内保持不变。
具体来说,slot
变量的作用包括:
- 线程标识:每个槽位都有一个唯一的标识符,用于区分不同的线程。
- 线程状态管理:槽位中存储了线程的当前状态,例如是否正在运行、是否被挂起等。
- 事件通知:通过槽位中的事件(event),可以实现线程间的同步和通信。
- 资源管理:槽位还可以用于管理线程的资源,例如内存分配、文件描述符等。
在当前的代码片段中,slot
变量是在 srv_master_thread
函数中声明的,用于为主线程分配一个槽位。在后续的代码中,这个槽位将被用于主线程的各种操作,例如等待事件、执行任务等。
以下是 slot
变量在代码中的具体使用示例:
slot = srv_reserve_slot(SRV_MASTER);
ut_a(slot == srv_sys->sys_threads);
在这段代码中,srv_reserve_slot
函数为主线程分配了一个槽位,并将其赋值给 slot
变量。然后,通过 ut_a
断言确保分配的槽位是正确的。
在 InnoDB 中,线程的槽位管理是非常重要的,因为它确保了线程的正确调度和资源的有效利用。通过 slot
变量,InnoDB 可以实现对线程的精细控制和管理。
SRV_FORCE_NO_BACKGROUND
SRV_FORCE_NO_BACKGROUND 是 MySQL InnoDB 存储引擎中的一个恢复模式参数,具体含义和作用如下:
含义
SRV_FORCE_NO_BACKGROUND 是 InnoDB 存储引擎在启动或恢复过程中可以使用的一个参数,用于控制 InnoDB 主线程(master thread)和后台清理线程(purge thread)的行为。
作用
当设置 SRV_FORCE_NO_BACKGROUND 参数时,它会阻止 InnoDB 的主线程和后台清理线程运行。这通常用于在数据库无法正常启动或存在严重损坏时,允许数据库以最小化风险的方式启动,以便进行数据恢复或其他维护操作。
具体来说,阻止这些线程运行可以防止在数据库启动过程中执行可能引发崩溃的操作,如 full purge 操作(完全清理已删除的数据页)。这有助于在数据库损坏时保持稳定,并允许管理员有机会进行进一步的诊断和修复。
使用场景
SRV_FORCE_NO_BACKGROUND 参数通常用于以下场景:
- 数据库无法正常启动:当数据库由于某种原因(如损坏、配置错误等)无法正常启动时,可以使用此参数尝试启动数据库,以便进行进一步的诊断和修复。
- 数据恢复:在数据恢复过程中,可能需要阻止后台线程的运行,以避免它们干扰恢复过程或进一步损坏数据。
- 紧急维护:在某些紧急情况下,可能需要立即启动数据库以进行某些必要的维护操作,而此时无法等待后台线程完成其任务。
注意事项
- 风险:使用 SRV_FORCE_NO_BACKGROUND 参数可能会带来一定的风险,因为它会阻止 InnoDB 存储引擎的正常清理和维护操作。因此,在启用此参数之前,应确保已经备份了所有重要数据。
- 临时使用:此参数通常应作为临时解决方案使用,以便进行进一步的诊断和修复。一旦问题解决,应尽快关闭此参数,以恢复 InnoDB 存储引擎的正常运行。
- 文档和社区:在决定使用此参数之前,建议查阅 MySQL 官方文档或相关社区论坛,以获取更多关于此参数的信息和使用建议。
综上所述,SRV_FORCE_NO_BACKGROUND 是 MySQL InnoDB 存储引擎中的一个重要恢复模式参数,用于在特定情况下控制 InnoDB 主线程和后台清理线程的行为。在使用此参数时,应谨慎考虑其潜在的风险和限制,并确保已经采取了适当的数据备份和恢复措施。
参考资料
mysql源码 srv0srv.cc
MarsCode AI
文心一言