MySQL 引擎特性 InnoDB 文件系统之文件物理结构(6)

当某个数据页上的数据被删光时,我们需要从其所在segmeng上删除该page(btr_page_free -->fseg_free_page --> fseg_free_page_low),回收的流程也比较简单:

首先如果是该segment的frag array中的page,将对应的slot设置为FIL_NULL, 并返还给表空间(fsp_free_page):

page在xdes entry中的状态置为空闲;

如果page所在Extent处于FSP_FULL_FRAG链表,则转移到FSP_FREE_FRAG中;

如果Extent中的page完全被释放掉了,则释放该Extent(fsp_free_extent),将其转移到FSP_FREE链表;

从函数返回

如果page所处于的Extent当前在该segment的FSEG_FULL链表上,则转移到FSEG_NOT_FULL链表;

设置Page在xdes entry的bitmap对应的XDES_FREE_BIT为true;

如果此时该Extent上的page全部被释放了,将其从FSEG_NOT_FULL链表上移除,并加入到表空间的FSP_FREE链表上(而非Segment的FSEG_FREE链表)。

释放Segment
当我们删除索引或者表时,需要删除btree(btr_free_if_exists),先删除除了root节点外的其他部分(btr_free_but_not_root),再删除root节点(btr_free_root)

由于数据操作都需要记录redo,为了避免产生非常大的redo log,leaf segment通过反复调用函数fseg_free_step来释放其占用的数据页:

首先找到leaf segment对应的Inode entry(fseg_inode_try_get);

然后依次查找inode entry中的FSEG_FULL、或者FSEG_NOT_FULL、或者FSEG_FREE链表,找到一个Extent,注意着里的链表元组所指向的位置实际上是描述该Extent的Xdes Entry所在的位置。因此可以快速定位到对应的Xdes Page及Page内偏移量(xdes_lst_get_descriptor);

现在我们可以将这个Extent安全的释放了(fseg_free_extent,见后文);

当反复调用fseg_free_step将所有的Extent都释放后,segment还会最多占用32个碎片页,也需要依次释放掉(fseg_free_page_low)

最后,当该inode所占用的page全部释放时,释放inode entry:

如果该inode所在的inode page中当前被用满,则由于我们即将释放一个slot,需要从FSP_SEG_INODES_FULL转移到FSP_SEG_INODES_FREE(更新第一个page);

将该inode entry的SEG_ID清除为0,表示未使用;

如果该inode page上全部inode entry都释放了,就从FSP_SEG_INODES_FREE移除,并删除该page。

non-leaf segment的回收和leaf segment的回收基本类似,但要注意btree的根节点存储在该segment的frag arrary的第一个元组中,该Page暂时不可以释放(fseg_free_step_not_header)

btree的root page在完成上述步骤后再释放,此时才能彻底释放non-leaf segment

索引页

ibd文件中真正构建起用户数据的结构是BTREE,在你创建一个表时,已经基于显式或隐式定义的主键构建了一个btree,其叶子节点上记录了行的全部列数据(加上事务id列及回滚段指针列);如果你在表上创建了二级索引,其叶子节点存储了键值加上聚集索引键值。本小节我们探讨下组成索引的物理存储页结构,这里默认讨论的是非压缩页,我们在下一小节介绍压缩页的内容。

每个btree使用两个Segment来管理数据页,一个管理叶子节点,一个管理非叶子节点,每个segment在inode page中存在一个记录项,在btree的root page中记录了两个segment信息。

当我们需要打开一张表时,需要从ibdata的数据词典表中load元数据信息,其中SYS_INDEXES系统表中记录了表,索引,及索引根页对应的page no(DICT_FLD__SYS_INDEXES__PAGE_NO),进而找到btree根page,就可以对整个用户数据btree进行操作。

索引最基本的页类型为FIL_PAGE_INDEX。可以划分为下面几个部分。

Page Header
首先不管任何类型的数据页都有38个字节来描述头信息(FIL_PAGE_DATA, or PAGE_HEADER),包含如下信息:

MacrobytesDesc
FIL_PAGE_SPACE_OR_CHKSUM   4   在MySQL4.0之前存储space id,之后的版本用于存储checksum  
FIL_PAGE_OFFSET   4   当前页的page no  
FIL_PAGE_PREV   4   通常用于维护btree同一level的双向链表,指向链表的前一个page,没有的话则值为FIL_NULL  
FIL_PAGE_NEXT   4   和FIL_PAGE_PREV类似,记录链表的下一个Page的Page No  
FIL_PAGE_LSN   8   最近一次修改该page的LSN  
FIL_PAGE_TYPE   2   Page类型  
FIL_PAGE_FILE_FLUSH_LSN   8   只用于系统表空间的第一个Page,记录在正常shutdown时安全checkpoint到的点,对于用户表空间,这个字段通常是空闲的,但在5.7里,FIL_PAGE_COMPRESSED类型的数据页则另有用途。下一小节单独介绍  
FIL_PAGE_SPACE_ID   4   存储page所在的space id  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/92d804ea01a22ee9e899ff74b884f3f1.html