MySQL系列:innodb源码分析之重做日志结构(二)

2015-01-23 22:04:52 · 作者: · 浏览: 15
lint next_archived_file_no; /*下一个归档的文件编号*/ ulint next_archived_offset; /*下一个归档的偏移量*/ dulint scanned_lsn; byte* checkpoint_buf; /*本log group保存checkpoint信息的缓冲区*/ UT_LIST_NODE_T(log_group_t) log_groups; }log_group_t;

?

上面结构定义中的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