Chinaunix首页 | 论坛 | 博客
  • 博客访问: 744775
  • 博文数量: 38
  • 博客积分: 587
  • 博客等级: 中士
  • 技术积分: 579
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-17 14:32
文章存档

2013年(15)

2012年(23)

分类: Mysql/postgreSQL

2013-04-22 17:17:15

本文尝试对InnoDB表空间管理进行一个大致的分析,为了避免混淆,对比较关键的一些名词使用代码中的原文表示。另外本文假定读者已经基本了解MySQL/InnoDB相关的一些基础知识和概念。


上图是InnoDB很经典的一张关于表空间组织结构图,所谓表空间实际是InnoDB对其需要持久化的数据文件进行的一种物理组织格式,代码主要在fsp/fsp0fsp.c文件中,主要涵盖了所有关于segment,extent,page相关物理结构的组织和管理。


. page基本概念


page innodb管理其物理文件的一个基本单位,默认大小为16K,include/univ.i文件中定义:

  1. /* The 2-logarithm of UNIV_PAGE_SIZE: */
  2. #define UNIV_PAGE_SIZE_SHIFT    14
  3. /* The universal page size of the database */
  4. #define UNIV_PAGE_SIZE     (1 << UNIV_PAGE_SIZE_SHIFT)

page innoDB用来存放BTree节点,数据,segment inode等,其完整的类型定义在 include/fil0fil.h中定义:

  1. /** File page types (values of FIL_PAGE_TYPE) @{ */
  2. #define FIL_PAGE_INDEX     17855    /*!< B-tree node */
  3. #define FIL_PAGE_UNDO_LOG    2    /*!< Undo log page */

而象page type这样标识一个page类型的元数据信息都是存放在fil header中,fil header的定义也在include/fil0fil.h中:主要字段包括:

  1. #define FIL_PAGE_OFFSET    4 //page在表空间内的page no(页号)
  2. #define FIL_PAGE_PREV 8 //前一个页的page no
  3. #define FIL_PAGE_NEXT     12 //下一个页的page no
  4. #define FIL_PAGE_TYPE     24 //page类型
  5. #define FIL_PAGE_DATA     38 //fil header结束位置

这里需要说明的是:

  1. page no页号是相对于整个表空间的,而一个表空间可以包含有多个文件,而这个页号则是一直连续下去。

  2. 每个page都存放了其前后页的page no

  3. fil header结束位置是38 即整个fil header占用38个字节,这38字节是所有类型page都必须要有的,根据page类型不同后续会说明在这38字节之后还有其它的元数据信息需要存储。

当然关于page我们这里只简单描述了fil header,实际还有很多内容我们后续在依次讨论

. Extent基本概念。

page实际是一个比较小的物理组织单位,那么我们需要一个更大一点的单位来组织page,这个单位就是extent(称为簇或者区),一个extent管理64page,这个定义在include/fsp0types.h文件中定义:

  1. /** File space extent size (one megabyte) in pages */
  2. #define    FSP_EXTENT_SIZE     (1 << (20 – UNIV_PAGE_SIZE_SHIFT))

那么extent又是一个什么样的组织结构,它如何被存储的呢?实际上所谓的extent实际是通过一个叫extent descriptor(簇描述符)来表示的,具体定义在fsp/fsp0fsp.c中:

  1. /*     EXTENT DESCRIPTOR
  2. =================
  3. File extent descriptor data structure: contains bits to tell which pages in
  4. the extent are free and which contain old tuple version to clean. */
  5. /*-------------------------------------*/
  6. #define    XDES_ID     0    /* The identifier of the segment to which this extent belongs */
  7. #define XDES_FLST_NODE     8    /* The list node data structure for the descriptors */
  8. #define    XDES_STATE     (FLST_NODE_SIZE + 8) /* contains state information of the extent */
  9. #define    XDES_BITMAP     (FLST_NODE_SIZE + 12) /* Descriptor bitmap of the pages in the extent */
  10. /*-------------------------------------*/

实际上每64page就会有对应的一个extent descriptor存在,主要目的是标识这64page的状态(空闲,半空闲,还是保留给某个segment使用),以及能够快速从这64page中找到空闲的page

这里分别解释下:

  1. XDES_ID 存放该extent所属segmentid

  2. XDES_FLST_NODE实际是一个文件链表节点,这样可以把extent descriptor组织成一个链表,实际上我们在extent更上层管理extent时会把extent链在一起组成链表,那么实际链表的节点就是extent descriptor的这个字段,比如某个segmentextent free list和表空间的extent frag list都是通过这个节点组织extent链表的,这个后续详细说明

  3. XDES_STATE标识该extent descriptor所代表的extent的所属状态,定义如下:

  1. /* States of a descriptor */
  2. #define    XDES_FREE     1    /* extent is in free list of space */
  3. #define    XDES_FREE_FRAG     2    /* extent is in free fragment list of space */
  4. #define    XDES_FULL_FRAG     3    /* extent is in full fragment list of space */
  5. #define    XDES_FSEG     4    /* extent belongs to a segment */

    4. 最后的一个字段bitmap用来判断这个extent中哪些page是空闲的。

这样算下来一个extent descriptor会占用40字节

  1. /* File extent data structure size in bytes. */
  2. #define    XDES_SIZE     \
  3. (XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))

XDES_SIZE = 24 byte + (64 * 2) bit = 40 byte

. Extent descriptor page 基本概念

分析过extent是通过extent descriptor来表示的,那么我们自然关心这个descriptor如何存储。

实际上extent descriptor也是存储在一个page中的,那么一个page16K,而一个descriptor只有40字节,所以一个page肯定可以存放很多个extent descriptor,那么我们就管这个专门用来存放extent descriptorpage 称为extent descriptor page

代码中使用了UNIV_PAGE_SIZE这个定义,作为一个extent descriptor page能够管理的page数量,也就是一个extent descriptor page 可以存放 16K / 64 = 256 extent descriptor

熟悉了extent descriptor page的基本概念后,我们具体看下这个page的结构:

实际上extent descriptor在该页上存储的位置从该页的第150字节开始依次存储,定义在fsp/fsp0fsp.c中如下:

  1. /* Offset of the descriptor array on a descriptor page */
  2. #define    XDES_ARR_OFFSET     (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)

这里涉及一个FSP_HEADER我们后续再说,也就是需要记住对于extent descriptor page来说,其extent descriptor 位置是在 fil header + fsp header之后存储的,如图:

. Extent descriptor page 的布局。

最后一个我们需要了解的是关于extent descriptor page本身是如何在表空间文件内布局的。

因为一个descriptor page可以描述16K个页,所以innodb在每16K个页间插入一个descriptor page,这样整个extent就完整的组织起来了,也就是说一个表空间的page 0 page 16384 , page 2 * 16384 ...都是extent descriptor page

阅读(2009) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~