MySQL系列:innodb源码分析之page结构解析(一)

2015-01-25 21:29:27 · 作者: · 浏览: 6
在表空间结构分析当中,我们知道innodb的最小物理存储分配单位是page页,在MySQL-3.23版本的 源码中,页只有两种页,一种是index page,一种是undo page。其类型值定义在fil0fil.h当中。 FIL_PAGE_INDEX 数据索引页,在表空间的inode page和xdes page都是属于这类。 FIL_PAGE_UNDO_LOG 事务回滚日志页。 在这里我们主要分析的是 index page,undo log page在事务部分来介绍。不管是index page还是undo log page都是由三部分组成,page_header、page_body、page_trailer三部分组成。针对index page来分析者三部分结构。

1.page header

page header是page的头信息,占用38个字节,分别存储以下信息: FIL_PAGE_SPACE 4字节 page所属的表空间的space id FIL_PAGE_OFFSET 4字节 page no,一般是在表空间的物理偏移量 FIL_PAGE_PREV 4 字节 前一页的page no (B+tree的叶子节点是通过链表串起来的,有前后关系) FIL_PAGE_NEXT 4字节 后一页的page no FIL_PAGE_LSN 8字节 更改记录时最大的redo log lsn,一般用在redo log恢复时使用 FIL_PAGE_TYPE 2字节 page的类型 FIL_PAGE_FILE_FLUSH_LSN 8字节 space文件最后被flush是的redo log lsn,这个值只会在space的第一个页中被设置 FIL_PAGE_ARCH_LOG_NO 4字节 最后被归档的archive log file 序号,这个值只会在space的第一个页中被设置

2.page trailer

page trailer是在文件末尾的最后8个字节, 低位4个字节是用来表示page页中数据的checksum,高位4位是用来存储FIL_PAGE_LSN的部分信息,关于checksum的计算是通过buf_calc_page_checksum这个函数来结算得到的,基本是通过对page中数据作为参数用ut_fold_binary来快速计算得到。在后续的版本中,page checksum是可以选择其他算法来做计算。这两个字在页保存到物理磁盘的时会进行更行,在页从物理磁盘读取出来的时候会被校验。宗旨就是保证页的完整性。

3.page body

index page body是由5部分组成,分别是body header、recorders、free recorders、free heap和page directory 组成。body header的结构定义如下:
#define	PAGE_N_DIR_SLOTS     0     /*page directory拥有的slot个数*/
#define PAGE_HEAP_TOP         2     /*heap中空闲位置的偏移量*/
#define PAGE_N_HEAP             4     /*heap中的记录数,所有分配出去的记录数,free rec + PAGE_N_RECS + 2*/
#define PAGE_FREE                   6     /*指向page中空闲空间的偏移量*/
#define PAGE_GARBAGE           8     /*已删除的记录字节数,用于重分配*/
#define PAGE_LAST_INSERT     10    /*最后插入记录的位置*/
#define PAGE_DIRECTION        12    /*记录的操作方向,PAGE_LEFT PAGE_RIGHT PAGE_SAME_REC PAGE_SAME_PAGE PAGE_NO_DIRECTION*/
#define PAGE_N_DIRECTION    14    /*同一方向连续插入的记录数*/
#define PAGE_N_RECS              16    /*页中存在的记录数,不包括infimum和supremum*/
#define PAGE_MAX_TRX_ID     18    /*修改当前页最大的事务ID*/
#define PAGE_HEADER_PRIV_END	 26
#define PAGE_LEVEL                 28     /*当前页在索引树的层位置*/
#define PAGE_BTR_SEG_LEAF   36     /*B+树叶子节点所在段的segment header信息*/
define PAGE_BTR_SEG_TOP	 (36 + FSEG_HEADER_SIZE)     /*B+树非叶子节点所在段的segment header信息*/
innodb在把真个页可以用的空间当着一个heap,当需要插入记录的时候,首先会在PAGE FREE中找是否有合适的记录 可以用,如果没有,就会在PAGE_HEAP_TOP的偏移上分配一个指定大小的rec_t的记录块,并将记录案主键值插入到 recorders当中。那么recorders是通过什么样的方式组织的呢?

3.1记录的组织方式

在index page body中,rec(记录)组织方式采用的是单向链表的方式来组织的,最前面一个记录和最后面一个记录是innodb定义的虚拟记录,叫做infimum和supremum。这两个记录的物理物质是在body header后面紧接着的连个记录。 其偏移如下:
#define PAGE_DATA             (PAGE_HEADER + 36 + 2 * FSEG_HEADER_SIZE)
#define PAGE_INFIMUM       (PAGE_DATA + 1 + REC_N_EXTRA_BYTES)           /*本page中索引最小的记录位置*/
#define PAGE_SUPREMUM	 (PAGE_DATA + 2 + 2 * REC_N_EXTRA_BYTES + 8)     /*本page中索引最大的记录位置*/
这两条记录在index page创建的时候就会被创建,参见page_create函数,其他的记录是插入在其之间,入下示意图: \

3.2body free list

除了有效记录以外,page中还有一类是之间使用过但被删除的记录,这类记录不会直接回收到heap中(因为rec是逻辑 顺序关系进行组织的,无法直接回收到heap中),innodb采用了page free recorders列表来组织和管理,通过 body header中的PAGE_FREE来进行定位,PAGE_FREE指向第一个被删除的rec记录的页内偏移量。 示意图如下: \
body header除了用PAGE_FREE来管理释放的记录外,还使用了PAGE_GARBAGE来管理其空间大小,这个值表示所有删除的记录占用空间字节总和,以便删除的记录可以重复被使用,提高空间的使用率。 除了recorders和free recorders外,还有一个连续的空间,这个空间是用来做记录分配的,只有当free recorders中没有合适的记录空间的时候,才会在这个连续空间上分配记录。这个空间的地址偏移是在PAGE_HEAP_TOP中的。

3.3directory slots

innodb为了快速查找记录,在body的后面定义了一个称之为directory的目录槽(slots),每个槽位占用两个字节,采用的是逆序存储,也就是说mifimum的槽位总是在body最后2个字节上,其他的一次类推。每个槽位可以存储多个纪录。以下是各种slot的记录数描述范围(n_owned):

Infimum slot owned

只有