我们使用mysql常使用innodb存储引擎,它包括两种,一种是innobase,另外一种是innodb plugin。今天主要介绍innodb plugin的file I/O操作,innodb plugin存储引擎的文件操作主要包括下面三个重要的结构体:
fil_node_struce 一个node对应着一个文件
fil_space_struct 一个space对应着一个tablespace
fil_system_struct innodb tablespace memory cache
下面分别简单介绍三个结构体,这三个结构体的一些成员变量可以标示这三个结构体所构成的关系,它们是如何关联在一起的。
第一个重要的结构体,node是数据文件在内存中对应的一个管理结构
/** File node of a tablespace or the log data space */
struct fil_node_struct {
//指向这个node所在的tablespace
fil_space_t* space;
//这个文件的名字,包含了路径
char* name; /*!< path to the file */
//这个node是否处于打开状态,这个依附于下面的成员变量hanlde的值
ibool open; /*!< TRUE if file open */
//文件打开的句柄
os_file_t handle; /*!< OS handle to the file, if file open */
//这个node所对应的文件,是否使用raw disk
ibool is_raw_disk;
//文件大小,多少个页
ulint size; /*!< size of the file in database pages, 0 if
not known yet; the possible last incomplete
megabyte may be ignored if space == 0 */
//多少个pending i/o,mysql有自己的异步I/O机制,接下来三个参数也都与此有关
ulint n_pending;
/*!< count of pending i/o’s on this file;
closing of the file is not allowed if
this is > 0 */
ulint n_pending_flushes;
/*!< count of pending flushes on this file;
closing of the file is not allowed if
this is > 0 */
ib_int64_t modification_counter;/*!< when we write to the file we
increment this by one */
ib_int64_t flush_counter;/*!< up to what
modification_counter value we have
flushed the modifications to disk */
//这是一个结构体,表示双向链表中的一个field,通过它可以知道前一个node,后一个node,这些node都属于同一个表空间
UT_LIST_NODE_T(fil_node_t) chain;
/*!< link field for the file chain */
//这是一个结构体,表示LRU双向链表中的一个field,通过它可以知道前一个node,后一个node,这些node可能属于不同的表空间,这个LRU的base node存在fil_system_struct中。
UT_LIST_NODE_T(fil_node_t) LRU;
/*!< link field for the LRU list */
ulint magic_n;/*!< FIL_NODE_MAGIC_N */
};
第二个重要的结构体,表空间space,从逻辑上讲,一个表空间space包含一个node,或者多个node
/** Tablespace or log data space: let us call them by a common name space */
struct fil_space_struct {
char* name; /*!< space name = the path to the first file in it */
//每个表空间都有唯一的一个ID
ulint id; /*!< space id */
//表空间的version
ib_int64_t tablespace_version;
ibool mark; /*!< this is set to TRUE at database startup if
the space corresponds to a table in the InnoDB
data dictionary; so we can print a warning of
orphaned tablespaces */
//这个表空间停止新的i/o操作,比如文件改名操作
ibool stop_ios;
ibool stop_ibuf_merges;
/*!< we set this TRUE when we start
deleting a single-table tablespace */
//是否正在被删除
ibool is_being_deleted;
/*!< this is set to TRUE when we start
deleting a single-table tablespace and its
file; when this flag is set no further i/o
or flush requests can be placed on this space,
though there may be such requests still being
processed on this space */
//这个表空间的用途,主要有三种FIL_TABLESPACE, FIL_LOG, or FIL_ARCH_LOG
ulint purpose;
//双向链表的基结点,管理这个表空间所有的nodes
UT_LIST_BASE_NODE_T(fil_node_t) chain;
/*!< base node for the file chain */
//这个表空间的大小
ulint size; /*!< space size in pages; 0 if a single-table
tablespace whose size we do not know yet;
last incomplete megabytes in data files may be
ignored if space == 0 */
ulint flags; /*!< compressed page size and file format, or 0 */
ulint n_reserved_extents;
/*!< number of reserved free extents for
ongoing operations like B-tree page split */
//这个表空间的pending flushes个数,如果这个值>0,这个表空间不允许删除。
ulint n_pending_flushes;
//mysql特有的insert buffer,你还记得它的作用是什么吗?它存在什么地方?
ulint n_pending_ibuf_merges;/*!< this is positive
when merging insert buffer entries to
a page so that we may need to access
the ibuf bitmap page in the
tablespade: dropping of the tablespace
is forbidden if this is positive */
//两个hash表,提供两种快速访问node,或者table的方法
hash_node_t hash; /*!< hash chain node */
hash_node_t name_hash;/*!< hash chain the name_hash table */
#ifndef UNIV_HOTBACKUP
//定义的一个latch,来控制这个space结构体的并发操作
rw_lock_t latch; /*!< latch protecting the file space storage
allocation */
#endif /* !UNIV_HOTBACKUP */
//双向链表的一个field,通过这个成员变量,可以找到前一个unflushed space,以及下一个unflushed space,双向链表的基结点存在于fil_system_struce的unflushed_spaces里
UT_LIST_NODE_T(fil_space_t) unflushed_spaces;
ibool is_in_unflushed_spaces; /*!< TRUE if this space is
currently in unflushed_spaces */
//双向链表的一个field,这个双向链表保存整个系统所有的tablespace,这个双向链表的基结点存在于fil_system_struct的space_list中
UT_LIST_NODE_T(fil_space_t) space_list;
/*!< list of all spaces */
ulint magic_n;/*!< FIL_SPACE_MAGIC_N */
};
/** Value of fil_space_struct::magic_n */
#define FIL_SPACE_MAGIC_N 89472
第三个重要的结构体tablespace memory cache,它是一个入口,通过它可以找到所有的spaces,node的LRU链表,待刷新的unflushed spaces
/** The tablespace memory cache */
typedef struct fil_system_struct fil_system_t;
/** The tablespace memory cache; also the totality of logs (the log
data space) is stored here; below we talk about tablespaces, but also
the ib_logfiles form a ‘space’ and it is handled here */
struct fil_system_struct {
#ifndef UNIV_HOTBACKUP
//定义一个mutex,用来保护对此结构的并发访问
mutex_t mutex; /*!< The mutex protecting the cache */
#endif /* !UNIV_HOTBACKUP */
//hash表,根据space_id能快速定位space
hash_table_t* spaces;
//hash表,根据space_name能快速定位到space
hash_table_t* name_hash;
//所有打开的,并且没有pending i/o的文件node,都会放入到LRU链表中进行淘汰,系统表空间,以及日志的文件不会放入到此LRU链表当中
UT_LIST_BASE_NODE_T(fil_node_t) LRU;
/*!< base node for the LRU list of the
most recently used open files with no
pending i/o’s; if we start an i/o on
the file, we first remove it from this
list, and return it to the start of
the list when the i/o ends;
log files and the system tablespace are
not put to this list: they are opened
after the startup, and kept open until
shutdown */
//所有发生了数据改写的space,都会入到unflushed_spaces,如果想知道哪些spaces需要刷i/o,只需要遍历此链表即可
UT_LIST_BASE_NODE_T(fil_space_t) unflushed_spaces;
/*!< base node for the list of those
tablespaces whose files contain
unflushed writes; those spaces have
at least one file node where
modification_counter > flush_counter */
//当前打开文件的个数
ulint n_open; /*!< number of files currently open */
//系统允许打开的文件个数,这是一个软限制,不是一个硬限制,如果是单表空间,这个成员变量所对应的innodb_open_files参数需要设大
ulint max_n_open; /*!< n_open is not allowed to exceed
this */
ib_int64_t modification_counter;/*!< when we write to a file we
increment this by one */
ulint max_assigned_id;/*!< maximum space id in the existing
tables, or assigned during the time
mysqld has been up; at an InnoDB
startup we scan the data dictionary
and set here the maximum of the
space id’s of the tables there */
ib_int64_t tablespace_version;
/*!< a counter which is incremented for
every space object memory creation;
every space mem object gets a
’timestamp’ from this; in DISCARD/
IMPORT this is used to check if we
should ignore an insert buffer merge
request */
//双向链表的基结点,管理着全部的spaces
UT_LIST_BASE_NODE_T(fil_space_t) space_list;
/*!< list of all file spaces */
};
/** The tablespace memory cache. This variable is NULL before the module is
initialized. */
static fil_system_t* fil_system = NULL;
这几个结构体里的UT_LIST_BASE_NODE_T(),UT_LIST_NODE_T(),可以看一下宏定义,以增强大家对以上三个结构体三者之间关系的理解。
#define UT_LIST_BASE_NODE_T(TYPE) struct { ulint count; /*!< count of nodes in list */ TYPE * start; /*!< pointer to list start, NULL if empty */ TYPE * end; /*!< pointer to list end, NULL if empty */ } #define UT_LIST_NODE_T(TYPE) struct { TYPE * prev; /*!< pointer to the previous node, NULL if start of list */ TYPE * next; /*!< pointer to next node, NULL if end of list */ } |
在Fil0fil.c文件里定义上如上的三个重要的结构体,里面还有很多函数,都是围绕着这三个结构体展开,这些函数完成innodb 的文件i/o操作。平时应多读读代码,在代码结构里,更容易去理解mysql innodb plugin的运行原理,对代码的理解,如果碰到一些bug,也可以知道怎么样绕开这个bug,这是一件挺有意思的事。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
作者
相关推荐
-
OpenWorld18大会:Ellison宣布数据库的搜寻和破坏任务
在旧金山举行的甲骨文OpenWorld 2018大会中,甲骨文首席技术官(CTO)兼创始人Larry Elli […]
-
ObjectRocket着力发展Azure MongoDB服务
MongoDB吸引了微软公司的注意力,微软公司计划针对运行于该公司2017年发布的Azure Cosmos D […]
-
2017年5月数据库流行度排行榜 MySQL与Oracle“势均力敌”
数据库知识网站DB-engines.com最近更新了2017年5月的数据库流行榜单。TechTarget继续与您一起分享最新的榜单情况。
-
2017年3月数据库流行度排行榜 Oracle卫冕之路困难重重
时隔一个月,数据库市场经过一轮“洗牌”,旧的市场格局是否会被打破,曾经占巨大市场份额的企业是否可能失去优势?