Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1744055
  • 博文数量: 107
  • 博客积分: 1715
  • 博客等级: 上尉
  • 技术积分: 3168
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-18 18:42
个人简介

阿里巴巴DBA,原去哪儿网DBA。专注于MySQL源码研究、DBA运维、CGroup虚拟化及Linux Kernel源码研究等。 github:https://github.com/HengWang/ Email:king_wangheng@163.com 微博 :@王恒-Henry QQ :506437736

文章分类

全部博文(107)

文章存档

2014年(2)

2013年(38)

2012年(67)

分类: Mysql/postgreSQL

2013-03-17 22:26:53

目的

       MySQL的日志子系统主要包括error log、binlog、general log三种类型的日志。TC_LOG数据结构及相关处理方法是日志子系统中为两阶段事务(2PC)提供的,并且在binlog中继承了该结构。本文主要对TC_LOG数据结构及主要处理方法进行分析,一方面为binlog分析处理做准备,另一方面进一步深入理解两阶段事务(2PC)日志的处理策略。

数据结构

       TC_LOG数据结构的定义在源码文件的sql/log.h中,其中在TC_LOG派生出两个子类,TC_LOG_DUMMY是一个假的类,派生类TC_LOG_MMAP,通过mmap策略实现事务日志的策略。主要的类方法包括:open()打开日志文件、close()关闭日志文件、log_xid()记录2PC事务日志id、unlog()删除2PC事务日志id四个操作。TC_LOG及子类关系图如下所示:

 



图1 TC_LOG类关系图

 

       首先,对子类TC_LOG_MMAP中的重要参数进行说明:filename是mmap的日志文件名;fd是文件描述符;file_length是日志文件的大小;npages是日志文件的页数,这是由于日志文件按照页进行组织;inited是一个流程状态参数,用于表明当前操作所处的状态;data是用于存储xid数据内容;pages、syncing、active、pool、pool_last是st_page结构体的指针,pages是st_page数据结构,用于组织数据页。日志页分为syncing、active、pool三种状态存在。pool_last指针指向pool队列中的最后一个元素;LOCK_active、LOCK_pool、LOCK_sync三个锁结构,用于并发控制访问日志;COND_pool和COND_active条件变量分别用于并发控制中,唤醒pool队列和active页访问。

       在TC_LOG_MMAP中,一个重要的结构体就是st_page,使得日志按照页的方式进行组织和操作。定义如下所示:

 

typedef struct st_page {

    struct st_page *next; // page a linked in a fifo queue

    my_xid *start, *end// usable area of a page

    my_xid *ptr;          // next xid will be written here

    int size, free;       // max and current number of free xid slots on the page

    int waiters;          // number of waiters on condition

    PAGE_STATE state;     // see above

    mysql_mutex_t lock; // to access page data or control structure

    mysql_cond_t  cond; // to wait for a sync

  } PAGE;

 

       由以上定义可知,日志页按照队列的方式进行组织,next指针指向下一个日志页;start和end指针分别指向页的第一个和最后一个位置;ptr指向下一个记录xid的位置;size是日志页可以存储xid的数目;free是空闲的存储空间数目;waiters是当前页处于条件等待的操作数目;state是当前页的状态,主要包括PS_POOL、PS_ERROR、PS_DIRTY三种状态;lock和cond分别用于并发控制日志页操作。

源码分析

       基于以上数据结构,进一步分析源码的实现策略,具体的参考源码文件sql/log.cc。以下对实现策略和处理方法进行详细分析。

       首先,根据源码可知,TC_LOG日志文件默认每页大小为8K、文件大小最小为3页,可以根据配置文件和启动参数指定日志文件大小。定义如下所示:

 

#define TC_LOG_PAGE_SIZE   8192

#define TC_LOG_MIN_SIZE    (3*TC_LOG_PAGE_SIZE)

 

TC_LOG_MMAP组织结构

       通过分析TC_LOG_MMAP::open()函数的处理逻辑,可知日志文件通过mmap将文件映射至内存,按照页进行组织分配,每一页按照页大小8K(windows下按照系统页大小分配)划分。第一页需要有一个页头信息,具体参考日志第一页组织格式。每一页中存储xid信息,通过页大小和xid占用的空间,计算出size和free。日志页通过next指针,组织成日志页的链式结构。在日志页分配后,将第一页作为active页,其他页为pool页。具体组织方式如下所示:

 



图2 TC_LOG_MMAP页组织结构

 

       在日志页的第一页中,有一个头信息,用于表示2PC日志类型文件。首先存储4个字节的文件唯一标示,然后一个字节存储支持2PC的存储引擎的数目。其中日志的第一页组织如下所示:




图3 TC_LOG_MMAP日志第一页结构

 

TC_LOG_MMAP日志页类型转换

       通过分析TC_LOG_MMAP的log_xid()和unlog()方法,可知TC_LOG_MMAP页状态转化过程如下所示:

 



图4 TC_LOG_MMAP日志页类型转换图

 

       在TC_LOG_MMAP日志页逻辑处理中,只有一页为active页,一个页处于syncing页,其他页处于pool页。首先从pool队列中,取出一页为active页。然后可以将xid存储在active页,并标示该页为PS_DIRTY状态,等待sync。syncing页是处于将页信息从内存同步到磁盘的过程,同步后的页添加到pool队列中,此时active页变为syncing页。

其中,从pool队列中取出一页为active页,有两种策略:

       1)取pool队列中的第一页,但是当第一页处于忙状态,即waiters不为0时,采用第2种策略;

       2)选取pool队列中free值最大且空闲的一页(free值越大表明空闲空间越大),作为active页。

       此外,从以上转换图和源码处理逻辑中可以发现,active页和syncing页在并发访问时,都是序列化的操作,syncing页的序列化是必须的,而active页是完全可以并行处理的。源码注释中解释到:syncing过程是整个处理的瓶颈(即IO操作过程是瓶颈),因此active页的序列化访问不会造成性能问题。但是当2PC事务频繁时,而IO的sync操作短暂阻塞时,会导致active页写满,由于active页是序列化的操作,如果2PC事务的实现依赖于日志的处理过程时,就会阻塞2PC事务的处理。

TC_LOG_MMAP日志时间周期

       TC_LOG_MMAP日志时间周期是指日志记录xid的时间和日志清除xid的时间。从2PC事务的理论来看,在prepare阶段时,调用TC_LOG_MMAP::log_xid()函数记录xid,在commit时,调用TC_LOG_MMAP::unlog()函数删除xid记录。这样可以保证2PC事务在prepare失败的时候,通过恢复策略进行恢复,保证数据的一致性。

TC_LOG_MMAP回滚

       TC_LOG_MMAP的回滚依赖于存储引擎的实现,只有支持2PC的存储引擎,才能进行数据的回滚。在回滚时,首先将日志文件的所有页中的xid信息(日志页中存在xid表明当前事务没有commit,是需要回滚的事务),全部插入的hash结构中,然后调用ha_recover()函数(sql/handler.cc)进行事务回滚,具体的回滚过程依赖存储引擎的回滚策略。

结论

       通过以上分析TC_LOG的数据结构、日志页结构以及实现的策略,对TC_LOG的整个处理逻辑有深入的理解。TC_LOG_MMAP使用mmap策略,将日志文件映射到内存,按照日志页的方式组织,可以有效提高并发访问的能力,并且日志的sync操作按照页的方式,可以将多次操作一次同步到磁盘。

       然而在设计中,active页的访问作为序列化操作,在极端情况下,从理论上推断可能会影响2PC事务的处理。具体的情况,还需要通过多种场景的测试获得真实的结果。

 

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

king_wangheng2013-03-18 18:58:18

Bean_lee:和兄弟的专注相比,我很汗颜啊。我搞得有点杂,不过,我要开始搞搞PostgreSQL。还要多向你学习。

客气了,工作需要,再加上自己的爱好,多多交流吧!

回复 | 举报

king_wangheng2013-03-18 18:58:15

Bean_lee:和兄弟的专注相比,我很汗颜啊。我搞得有点杂,不过,我要开始搞搞PostgreSQL。还要多向你学习。

客气了,工作需要,再加上自己的爱好,多多交流吧!

回复 | 举报

Bean_lee2013-03-18 15:07:01

和兄弟的专注相比,我很汗颜啊。我搞得有点杂,不过,我要开始搞搞PostgreSQL。还要多向你学习。