ibd文件结构
MySQL版本为8.0
组成表空间的各个单位
上图是一张经典的关于页,区,段之间关系的视图,一个区由页组成,一个段由多个区组成。其中段是管理页的逻辑单位,有叶子节点段,非叶子节点段还有回滚段。区是地址连续的物理单位。
对于这张图,我们还需要一些解释,一个段中的不同区物理上不一定连续,且一个段可能只包含一个区中的一个页,而不是整个区(如果这个区专门用来分配碎片页的话)。
区与区之间地址连续,区可以属于一个段,也可以属于表空间。
初看IBD文件
默认情况下一个页的大小是16KB,下文也使用默认的页大小。dict_build_tablespace_for_table
函数会创建文件并分配FIL_IBD_FILE_INITIAL_SIZE=7
个页的空间。
/* We create a new single-table tablespace for the table.
We initially let it be 4 pages:
- page 0 is the fsp header and an extent descriptor page,
- page 1 is an ibuf bitmap page,
- page 2 is the first inode page,
- page 3 will contain the root of the clustered index of
the table we create here. */
区
之前提到过,区是页管理的物理单位,当页大小为16KB时,区大小为64个页。并且每16K(这个值恒等于页大小)个页就有一个区描述符页(extent descriptor page)。page 0 是表空间头页,也是区描述页,在介绍page 0的字段前,我们先来看一下文件头。
Fil Header
其实我觉得文件头可以回来再看,大家先跳过吧23333。
下图(绿绿的图都是)来自leviathan。对于每个页都有以下的文件头,占据38字节,以及8字节的文件尾。
其中各个字段的意思引用自jcole
- The page type is stored in the header. This is necessary in order to parse the rest of the page data. Pages are allocated for file space management, extent management, the transaction system, the data dictionary, undo logs, blobs, and of course indexes (table data).
- The space ID is stored in the header.
- The page number is stored in the header once the page has been initialized. Checking that the page number read from that field matches what it should be based on the offset into the file is helpful to indicate that reading is correct, and this field being initialized indicates that the page has been initialized.
- A 32-bit checksum is stored in the header, and an older format (and broken) 32-bit checksum is stored in the trailer. The older checksum could be deprecated and that space reclaimed at some point.
- Pointers to the logical previous and next page for this page type are stored in the header. This allows doubly-linked lists of pages to be built, and this is used for
INDEX
pages to link all pages at the same level, which allows for e.g. full index scans to be efficient. Many page types do not use these fields.- The 64-bit log sequence number (LSN) of the last modification of the page is stored in the header, and the low 32-bits of the same LSN are stored in the trailer.
- A 64-bit “flush LSN” field is stored in the header, which is actually only populated for a single page in the entire system, page 0 of space 0. This stores the highest LSN flushed to any page in the entire system (all spaces). This field is a great candidate for re-use in the rest of the space.
FSP Header(page 0)
FSP Header
中字段的释义大多可以在源码fsp0fsp.h:130
中找到。在继续介绍之前,我们需要先解决这个问题,一个页,在内存中,可以用指针直接获取其内容。但如果是磁盘上的页呢?
InnoDB使用了fil_addr_t
这个类型表示,这个类型占据6个字节,前4个字节表示页序号,后2个字节表示页内偏移。
Macro | bytes | Desc |
---|---|---|
FIL_ADDR_PAGE | 4 | Page No |
FIL_ADDR_BYTE | 2 | Page内的偏移量 |
在FSP Header页中,如下图所示蓝色的字段,比如FSP_FREE
,FSP_FREE_FRAG
都是FLST_BASE_NODE
,占用16个字节。
Macro | bytes | Desc |
---|---|---|
FLST_LEN | 4 | 存储链表的长度 |
FLST_FIRST | 6 | 指向链表的第一个节点 |
FLST_LAST | 6 | 指向链表的最后一个节点 |
XDES Entry
页描述符中 FLST_PREV
,和FLST_NEXT
都是fil_addr_t
类型。
上图是FSP_Header
中的各个字段,我们此处先观察XDES Entry
,在这里每个XDES Entry
占据40字节。每个字段的意思分别是:
XDES ID
所属segment的id;如果没有则值为0,表示属于表空间,位于FSP_FREE
,FSP_FREE_FRAG
,FSP_FULL_FRAG
链表中的一个。FLST_PREV
类型就是fil_addr_t
,指向所在链表前一个XDES Entry
中的FLST_PREV
(不是指向XDES_ID
字段)。FLST_PREV
和FLST_NEXT
在代码中合为XDES_FLST_NODE
XDES_STATE
表示当前的区描述符的状态,位于表空间还是属于段,碎片页还是已经被完全使用。XDES_BITMAP
为16Bytes
即16 * 8
bits,其中一个Page
占用两个bit
用来表示Page
是否被占用。
FSP_SPACE_ID
表示该Tablespace的IDFSP_SIZE
表示目前Tablespace
有多少个Page
FSP_FREE_LIMIT
表示目前在空闲的Extent
上最小的尚未被初始化的Page
的Page Number
FSP_SPACE_FLAGS
表示Tablespace
的标志位FSP_FRAG_N_USED
表示FSP_FREE_FRAG
中已经使用的Page数量FSP_FREE
表示所有的Page
均为空闲的Extent
FSP_FREE_FRAG
表示Extent
中尚有Page
未被使用FSP_FULL_FRAG
表示Extent
的所有的Page
均已被使用FSP_SEG_ID
表示下一个未被使用的Segment ID
FSP_SEG_INODES_FULL
表示Segment Page
的所有的Inode
均已被使用FSP_SEG_INODES_FREE
表示Segment Page
存在空闲的Inode
Inode Page(Page 2)
Tablespace
的第三个Page
是关于Segment
信息的,类型为FIL_PAGE_INODE
,其中一个Inode
可以理解为管理一个Segment
元信息单元:
下图38字节偏移开始的字段为FSEG_INODE_PAGE_NODE
,和XDES_FLST_NODE
功能相同,即2个fil_addr_t
,分别指向前后两个Inode Page。
在一个Inode
即一个Segment
中:
FSEG_ID
表示Segment
的ID
FSEG_NOT_FULL_N_USED
表示Segment
中被使用的Page
数量FSEG_FREE
表示所有Page
均为空闲的Extent
FSEG_NOT_FULL
表示部分Page
空闲的Extent
FSEG_FULL
表示所有Page
均被使用的Extent
FSEG_MAGIC_N
表示一个magic numbe
用于Debug
Slot
表示一个Page