?
上面结构定义中的spaceid是对应fil0fil中的fil_space_t结构,一个fil_space_t结构可以管理多个文件fil_node_t,关于fil_node_t参见这里。
3.1.1LSN与组内偏移
在log_goup_t组内日志模块当中,其中比较重要的是关于LSN与组内偏移之间的换算关系。在组创建时,会对lsn和对应lsn_offset做设置,假如 初始化为 group lsn = 1024, group lsn_offset = 2048,group由3个10240大小的文件组成,LOG_FILE_HDR_SIZE = 2048, 我们需要知道buf lsn = 11240对应的组内offset的偏移是多少,根据log_group_calc_lsn_offset函数可以得出如下公式:group_size = 3 * 11240;
相对组起始位置的LSN偏移 = (buf_ls - group_ls) + log_group_calc_size_offset(lsn_offset ) = (11240 - 1024) - 0 = 10216;
lsn_offset = log_group_calc_lsn_offset(相对组起始位置的LSN偏移 % group_size) = 10216 + 2 * LOG_FILE_HDR_SIZE = 14312;
这个偏移一定是加上了文件头长度的。
?
3.1.2 file_header_bufs
?
file_header_bufs是一个buffer缓冲区数组,数组长度和组内文件数是一致的,每个buf长度是2048。其信息结构如下:

?
log_group_id 对应log_group_t结构中的id
file_start_lsn 当前文件其实位置数据对应的LSN值
File_no 当前的文件编号,一般在archive file头中体现
Hot backup str 一个空字符串,如果是hot_backup,会填上文件后缀ibackup。
File_end_ls 文件结尾数据对应的LSN值,一般在archive file文件中体现。
3.2 checkpoint
checkpoint是日志的检查点,其作用就是在数据库异常后,redo log是从这个点的信息获取到LSN,并对检查点以后的日志和PAGE做重做恢复。那么检查点是怎么生成的呢?当日志缓冲区写入的日志LSN距离上一次生成检查点的LSN达到一定差距的时候,就会开始创建检查点,创建检查点首先会将内存中的表的脏数据写入到硬盘,让后再将redo log buffer中小于本次检查点的LSN的日志也写入硬盘。在log_group_t中的checkpoint_buf,以下是它对应字段的解释:
LOG_CHECKPOINT_NO checkpoint序号,
LOG_CHECKPOINT_LSN 本次checkpoint起始的LSN
LOG_CHECKPOINT_OFFSET 本次checkpoint相对group file的起始偏移量
LOG_CHECKPOINT_LOG_BUF_SIZE redo log buffer的大小,默认2M
LOG_CHECKPOINT_ARCHIVED_LSN 当前日志归档的LSN
LOG_CHECKPOINT_GROUP_ARRAY 每个log group归档时的文件序号和偏移量,是一个数组
3.3 log_t
重做日志的写入、数据刷盘、建立checkpoint和归档操作都是通过全局唯一的,log_sys进行控制的,这是个非常庞大而又复杂的结构,定义如下:
typedef struct log_struct
{
byte pad[64]; /*使得log_struct对象可以放在通用的cache line中的数据,这个和CPU L1 Cache和数据竞争有和
直接关系*/
dulint lsn; /*log的序列号,实际上是一个日志文件偏移量*/
ulint buf_free; /*buf可以写的位置*/
mutex_t mutex; /*log保护的mutex*/
byte* buf; /*log缓冲区*/
ulint buf_size; /*log缓冲区长度*/
ulint max_buf_free; /*在log buffer刷盘后,推荐buf_free的最大值,超过这个值会被强制刷盘*/
ulint old_buf_free; /*上次写时buf_free的值,用于调试*/
dulint old_lsn; /*上次写时的lsn,用于调试*/
ibool check_flush_or_checkpoint; /*需要日志写盘或者是需要刷新一个log checkpoint的标识*/
ulint buf_next_to_write; /*下一次开始写入磁盘的buf偏移位置*/
dulint written_to_some_lsn; /*第一个group刷完成是的lsn*/
dulint written_to_all_lsn; /*已经记录在日志文件中的lsn*/
dulint flush_lsn; /*flush的lsn*/
ulint flush_end_offset; /*最后一次log file刷盘时的buf_free,也就是最后一次flush的末尾偏移量*/
ulint n_pending_writes; /*正在调用fil_flush的个数*/
os_event_t no_flush_event; /*所有fil_flush完成后才会触发这个信号,等待所有的goups刷盘完成*/
ibool one_flushed; /*一个log group被刷盘后这个值会设置成TRUE*/
os_event_t one_flushed_event; /*只要有一个group flush完成就会触发这个信号*/
ulint n_log_ios; /*log系统的io操作次数*/
ulint n_log_ios_old; /*上一次统计时的io操作次数*/
time_t last_printout_time;
ulint max_modified_age_async; /*异步日志文件刷盘的阈值*/
ulint max_modified_age_sync; /*同步日志文件刷盘的阈值*/
ulint adm_checkpoint_interval;
ulint max_checkpoint_age_async; /*异步建立checkpoint的阈值*/
ulint max_checkpoint_age; /*强制建立checkpoint的阈值*/
dulint next_checkpoint_no;
dulint last_checkpoint_lsn;
dulint next_checkpo