上一篇文章主要概述了下innodb page,extent,extent descriptor 等相关概念,本节将讨论下segment及space header等相关概念。
一. segment管理
1. segment inode概念
我们已经清楚innodb通过extent来管理一组物理文件空间上连续的page,而innodb通常需要管理大量这样的extent,比如innodb的btree存储需要占用大量的extent,所以需要有一个单位用来管理extent,这个单位就是segment,实际一颗btree就由2个segment组成,一个用来管理所有非叶节点,一个用来管理页节点,实际在innodb中通过一个叫segment inode的结构来存储segment相关的一些信息,也就是说每个segment都会对应有一个segment inode,我们看下它的定义:(fsp0fsp.c)
- #define FSEG_INODE_PAGE_NODE FSEG_PAGE_DATA
- //fil header后紧跟segment inode page文件链表域
-
#define FSEG_ARR_OFFSET (FSEG_PAGE_DATA + FLST_NODE_SIZE)
- //segment inode存储开始位置
-
/*-------------------------------------*/
-
#define FSEG_ID 0
- //segment inode所对应segment id
-
#define FSEG_NOT_FULL_N_USED 8 //半满extent链表使用数量
- #define FSEG_FREE 12 //空闲extent链表
- #define FSEG_NOT_FULL (12 + FLST_BASE_NODE_SIZE) //半满extent链表
- #define FSEG_FULL (12 + 2 * FLST_BASE_NODE_SIZE) //全满extent链表
- #define FSEG_MAGIC_N (12 + 3 * FLST_BASE_NODE_SIZE) //校验用magic数字
- #define FSEG_FRAG_ARR (16 + 3 * FLST_BASE_NODE_SIZE) //碎片页偏移地址
- #define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2) //碎片页数量(32个)
- #define FSEG_FRAG_SLOT_SIZE 4 //管理碎片页占用大小
首先segment inode数据也是连续存放在一个page中,开始位置也是第38字节(FIL_HEADER之后),那么我们管这个专门用来存放segment inode的page 叫做segment inode page,其中主要存在3个用来管理extent的文件链表,以及32个碎片页的地址,FSEG_FULL,FSEG_NOT_FULL,FSEG_FREE是3个文件头指针,通过extent descriptor的XDES_FLST_NODE将extent挂在对应的segment上,这样一个segment就可以管理其所属的extent了。那么读到这里还有跟问题需要解释,有了segment inode但是我们如何得知一个segment对应的inode在哪里呢?换句话说需要有个地方存放segment inode的位置。
2. segment header概念
我们知道segment inode也是顺序存放在一个特殊的page中的,那么我们只要知道这个page所在的space id和page no以及这个inode在该page中的offset就可以定位到这个inode了,所以在innodb中有如下定义:(fsp0types.h)
- #define FSEG_HDR_SPACE 0 /*!< space id of the inode */
-
#define FSEG_HDR_PAGE_NO 4 /*!< page number of the inode */
-
#define FSEG_HDR_OFFSET 8 /*!< byte offset of the inode */
-
-
#define FSEG_HEADER_SIZE 10 /*!< Length of the file system
-
header, in bytes */
实际存放这些信息的结构我们就叫它segment header, 我们前面讨论过一颗btree会有2个segment,非叶节点一个,页子节点一个,实际btree的root节点对应的page里就存放着这2个segment的segment header,定义如下(page0page.h):
- #define PAGE_BTR_SEG_LEAF 36 /* file segment header for the leaf pages in
-
a B-tree: defined only on the root page of a
-
B-tree, but not in the root of an ibuf tree */
-
-
#define PAGE_BTR_SEG_TOP (36 + FSEG_HEADER_SIZE)
-
/* file segment header for the non-leaf pages
-
in a B-tree: defined only on the root page of
-
a B-tree, but not in the root of an ibuf
-
tree */
这样通过访问btree的root节点我们很方便的能够找到所有节点对应的segment inode然后根据数据存储需要来分配和管理其对应的所有extent及page。
最后我们遗漏了一个最重要的结构没有讲 - space header:
二. Space Header 结构
虽然从前面的知识我们已经发现通过segment就可以把所有的page,extent等管理起来,但是实际上并不是所有的page都属于某个segment,比如用来存储segment信息的inode page本身就不是在segment内被分的,innodb中会通过segment来保留足够的空闲extent给特殊的场景使用,比如btree和rollback segment,而其它很多场景并不是从某个segment中分配空闲page的。
无论是segment还是独立的extent本身都需要一个结构来统一管理它们,这个结构就是space header,它是整个innodb表空间管理中的总管,所有跟extent,page,segment分配管理有关的事情实际都先要通过它,我们看下具体结构:(fsp0fsp.c)
- #define FSP_SPACE_ID 0 /* space id */
-
#define FSP_NOT_USED 4 /* this field contained a value up to
-
which we know that the modifications
-
in the database have been flushed to
-
the file space; not used now */
-
#define FSP_SIZE 8 /* Current size of the space in
-
pages */
-
#define FSP_FREE_LIMIT 12 /* Minimum page number for which the
-
free list has not been initialized:
-
the pages >= this limit are, by
-
definition, free; note that in a
-
single-table tablespace where size
-
< 64 pages, this number is 64, i.e.,
-
we have initialized the space
-
about the first extent, but have not
-
physically allocted those pages to the
-
file */
-
#define FSP_SPACE_FLAGS 16 /* table->flags & ~DICT_TF_COMPACT */
-
#define FSP_FRAG_N_USED 20 /* number of used pages in the
-
FSP_FREE_FRAG list */
-
#define FSP_FREE 24 /* list of free extents */
-
#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE)
-
/* list of partially free extents not
-
belonging to any segment */
-
#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE)
-
/* list of full extents not belonging
-
to any segment */
-
#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE)
-
/* 8 bytes which give the first unused
-
segment id */
-
#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE)
-
/* list of pages containing segment
-
headers, where all the segment inode
-
slots are reserved */
-
#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE)
大部分可以通过注释看懂,这里重点说明如下:
1. space header是在每一个extent descriptor page中存在,但只有第一个是使用的,其余只占用空间但不使用,也就是说space header存放在page 0中第38个字节后。
2. space header有3个文件链表头,FSP_FREE,FSP_FREE_FRAG,FSP_FULL_FRAG将所有不属于某个segment的extent链接在一起,也是通过extent descriptor的XDES_FLST_NODE域,分别代表空闲链表,半空闲链表,满链表。
3. space header中有2个链表头,将所有segment inode page链接在一起,通过segment inode page 的FSEG_INODE_PAGE_NODE节点域链接在一起,分别代表空闲inode page和满inode page链表。
比如innodb要创建一个segment并保留部分extent,那么它首先从space header中的FSP_FREE中拿走对应需要的extent,并把它挂到segment的FSEG_FREE链表上。而对应某些其它的page分配则可以直接通过space header的对应链表找到空闲的extent,再通过extent descriptor page找到对应空闲的page。
到这里整个表空间的基础数据结构就都讲完了,其它相关代码可以翻阅fsp0fsp.c查看
阅读(3074) | 评论(0) | 转发(0) |