typedef struct os_aio_slot_struct
{
 ibool	 is_read; /*是否是读操作*/
 ulint	 pos; /*slot array的索引位置*/
 ibool	 reserved; /*这个slot是否被占用了*/
 ulint	 len; /*读写的块长度*/
 byte*	 buf; /*需要操作的数据缓冲区*/
 ulint	 type; /*操作类型:OS_FILE_READ OS_FILE_WRITE*/
 ulint	 offset; /*当前操作文件偏移位置,低32位*/
 ulint	 offset_high; /*当前操作文件偏移位置,高32位*/
 os_file_t	 file; /*文件句柄*/
 char*	 name; /*文件名*/
 ibool	 io_already_done; /*在模拟aio的模式下使用,TODO*/
 void*	 message1;
 void*	 message2;
#ifdef POSIX_ASYNC_IO
 struct aiocb	control; /*posix 控制块*/
#endif
}os_aio_slot_t;
typedef struct os_aio_array_struct
{
 os_mutex_t	 mutex; /*slots array的互斥锁*/
 os_event_t	 not_full; /*可以插入数据的信号,一般在slot数据被aio操作后array_slot有空闲可利用的slot时发送*/
 os_event_t	 is_empty; /*array 被清空的信号,一般在slot数据被aio操作后array_slot里面没有slot时发送这个信号*/
 ulint	 n_slots; /*slots总体单元个数*/
 ulint	 n_segments; /*segment个数,一般一个对应n个slot,n = n_slots/n_segments,一个segment作为aio一次的操作范围*/
 ulint	 n_reserved; /*有效的slots个数*/
 os_aio_slot_t*	slots; /*slots数组*/
 os_event_t*	 events; /*slots event array,暂时没弄明白做啥用的*/
}os_aio_array_t;
内存结构关系图:在innodb中定义三种文件类型:表空间文件(ibdata*)、重做日志文件(ib_logfile*)和归档文件(ib_arch_log*)。一般innodb在运行的过程中,会同时打开很多个文件,这就要求对文件进行系统的管理和控制。在innodb中定义了一套基于fil_system_t、fil_space_t和fil_node_t的内存管理结构。每个文件对应的是一个fil_node_t,fil_node是存储的最小单元,多个同一模块的fil_node组成一个fil_space_t,所有的space组成一个fil_system_t,在innodb引擎里,只有一个fil_system_t对象。
fil_system_t管理着全局的文件操作资源,例如:文件打开的数量、打开文件的信号控制、fil_space_t的管理和索引等。以下是fil_system_t的结构定义:
typedef struct fil_system_struct
{
 mutex_t	 mutex; /*file system的保护锁*/
 hash_table_t*	spaces; /*space的哈希表,用于快速检索space,一般是通过space id查找*/
 ulint	 n_open_pending; /*当前有读写IO操作的fil_node个数*/
 ulint	 max_n_open; /*最大允许打开的文件个数*/
 os_event_t	 can_open; /*可以打开新的文件的信号*/
 
 UT_LIST_BASE_NODE_T(fil_node_t) LRU; /*最近被打开操作过的文件,用于快速定位关闭的fil_node*/
 UT_LIST_BASE_NODE_T(fil_node_t) space_list;	 /*file space的对象列表*/
}fil_system_t;
值得注意的是space的哈希表和LRU,这里为什么会出现用hash table来索引space呢?因为在实际的数据库系统中,fil_space_t是会非常多的,用哈希表能快速定位到需要操作的fil_space_t。LRU是用于保存最近被打开和被操作过的fil_node,为了避免频发的关闭和打开文件,LRU保存一定数量(500)的最近打开过的文件,这样可以提高系统的效率。
fil_space_t是用于管理同一模块的file_node,上层模块操作文件不是以文件名来做操作关联的,而是用space_id,
也就是说,所有的文件操作是通过space为单位进行操作的。fil_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来做控制,以下是它的控制函数:其结构定义如下:
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;
};
了解了他们三者的基本定义后,那他们之间的关系是怎么的?不用文字叙述,看下面的内存结构关系图: