MySQL系列:innodb引擎分析之文件IO(二)

2015-01-25 21:38:31 · 作者: · 浏览: 7
_space支持三种类型,分别是:
FIL_TABLESPACE 表空间space
FIL_LOG 重做日志space
FIL_ARCHI_LOG 归档日志space

fil_space_t的定义如下:

?

struct fil_space_struct
{
     char*	 name;                     /*space名称*/
     ulint	 id;                            /*space id*/
     ulint	 purpose;                 /*space的类型,主要有space table, log file和arch file*/
     ulint	 size;                         /*space包含的页个数*/
     ulint	 n_reserved_extents; /*预留的页个数*/
     hash_node_t	 hash;          /*chain node的HASH表*/
     rw_lock_t	 latch;               /*space操作保护锁,用于多线程并发*/
     ibuf_data_t*	ibuf_data;   /*space 对应的insert buffer*/
     ulint	 magic_n;                 /*魔法校验字*/

     UT_LIST_BASE_NODE_T(fil_node_t) chain;
     UT_LIST_NODE_T(fil_space_t)	 space_list;
};
fil_space通常是由一组文件组成,例如重做日志,一般是有3个文件组成一个group space用于重做日志记录。space通过成员latch可以支持多线程并发的。在innodb文件操作中,主要是通过space来做控制,以下是它的控制函数:
fil_space_create 创建一个fil_space
fil_space_free 销毁一个fil_space
fil_space_truncate_start 从space中删除fil_node,删除的总数据长度为trunc_len
fil_node_create 创建一个fil_node并加入到对应的space当中
fil_space_get_size 获得space的空间大小,以page为单位记
fil_io 指定space的io操作
fil_aio_wait aio异步方式的io操作等待,并根据完成状态更新space状态
fil_flush 指定space进行数据刷盘
fil_node_t是对单个文件进行管理,主要是管理文件的打开状态、文件句柄信息、文件的page数量和更新状态等。

?

其结构定义如下:

?

struct fil_node_struct
{
     char*	 name;                         /*文件路径名*/
     ibool	 open;                         /*文件是否被打开*/
     os_file_t	handle;                  /*文件句柄*/
     ulint	 size;                             /*文件包含的页个数,一个页是16K*/
     ulint	 n_pending;                 /*等待读写IO操作的个数*/
     ibool	 is_modified;               /*是否有脏也存在,flush是根据这个标志进行刷盘的*/
     ulint	 magic_n;                     /*魔法校验字*/
     UT_LIST_NODE_T(fil_node_t) chain;
     UT_LIST_NODE_T(fil_node_t) LRU;
};

值得注意的是当外部调用了fil_flush时,判断一个fil_node是否需要刷盘的必要条件是:
文件必须是打开的 open = TRUE
文件存在内存和硬盘数据不一致 is_modified = TRUE

?

?

了解了他们三者的基本定义后,那他们之间的关系是怎么的?不用文字叙述,看下面的内存结构关系图:

?

\

?

在了解了他们之间的基本关系后,那么一个io操作是怎么进行的?在这个模型里,一个io操作提交和被运行是比较复杂的。具体流程如下: 1.外部模块提交一个fil_io, 先会进行基本的io操作类型的判断和文件打开方式的判断。 2.然后进行对正在进行io操作的计数做判断,如果正在进行的io数量 > 最大文件打开数量的四分之三,唤醒所有aio的操作线程进行io处理,并进行sleep等待。 3.如果正在进行的io数量 = 最大文件打开数量,唤醒所有的aio操作线程进行io处理,并等待fil_system_t的can_open信号。 4.如果不满足2和3,找到需要受理io操作的space和node,并打开node对应的文件,打开文件时会对打开文件数量限制做判断,如果当前打开文件操作io的数量 + LRU里已经打开文件的数量>= 最大文件打开数量时,会取出LRU中最后一个fil_node进行文件关闭。然后在对新的io操作的fil_node文件进行打开。 5.fil_node文件打开后,调用os_aio进行io操作提交,然后等待io操作完成 6. io操作完成后,将完成io操作的fil_node放入LRU的第一个位置,并更改对应的fil_system/fil_space/fil_node的状态,最后触发一个fil_system的can open信号。 7.监听can_open的线程收到这个信号后,会跳到第4步进行自己的io操作提交。 流程图如下: \

?

3总结

总体来说,innodb的文件IO涉及到知识面很多,可以能短时间无法完全理解透彻,一般在阅读 源码的时候可以做一些基本的单元测试,这样有助于理解。弄清楚innodb的文件IO操作是非常有必要的,因为文件IO操作模块直接影响对innodb的日志系统的理解、表空间系统的理解。而且Innodb在文件IO模块的改进还是比较大的,尤其是引入Direct IO后。Direct IO很多 数据库都在用这个技术,除了innodb,oracle和淘宝的oceanbase都使用了这个技术, 关于Direct IO网络上资料很多,可以自行结合MySQL-5.6的innodb来做研究。