现在的位置: 首页 > 综合 > 正文

postgresql集群方案hot standby初级测试(四)——xlog详细解释header

2013年11月02日 ⁄ 综合 ⁄ 共 4160字 ⁄ 字号 评论关闭

xlog日志header部分详解

前些天,做了些实验,也确实能够证明手动同步xlog数据是可行性的,为了更深入的研究,我觉得研究下xlog的源码,并且打开xlog的二进制文件,读一读它里面的内容。


本文来自:http://blog.csdn.net/lengzijian/article/details/7836402


首先来看下xlog日志的结构图:


从上到下观察下:

xlog日志文件命名:

文件名 = 时间线 + 日志文件号(logid) + 段号(segmented)

        分为三部分,每个部分由8个16进制字符组成,时间线由1开始,日志文件号和段号由0开始,所以在系统中第一个事务日志文件名为:000000010000000000000000

 

       一个xlog文件日志备有256个段组成,每个段大小为16M,当最近的文件名有000000010000000000000000变为000000010000000100000000时,实际增加了256个段文件,但是逻辑上只增加了一个xlog日志文件。

 

每一个段文件又分为很多页面,每个一面的大小为一个块的大小:

include/pg_config.h:

#defineXLOG_BLCKSZ 8192        //块大小

//页面个数 = 16M / 8192bit = 2048

 

对于每一个日志页面,需要在器头部写一个头部信息XLogPageHeaderData,数据结构如下:

include/access/xlog_internal.h

 

typedef struct XLogPageHeaderData

{

    uint16          xlp_magic;              /* 校验位 */                                                                                                 

    uint16          xlp_info;               /* 标志位 */

    TimeLineID      xlp_tli;                /* 页面第一条记录的时间序列 */

    XLogRecPtr      xlp_pageaddr;           /* XLOG 页面首地址 */

} XLogPageHeaderData;


其中标志位xlp_info只使用最低两位“01”或者“10”或者11:

“01”表明该页的第一个XLOG记录着上一个页的最后一个XLOG记录,这样的记录会接在一个XLogContRecord结构体之后;

“10”表明该页的头部是一个长头部,既该页是XLOG段文件的首页;


这样头部标志位会有三种状态:

/* 如果记录跨越两个页面,这只该标志位到新的页面 */

#define XLP_FIRST_IS_CONTRECORD         0x0001                                                                                   

/*这里就是之前说过的表示该页是xlog段文件的首页 */

#define XLP_LONG_HEADER                         0x0002

/* 表示既是首页也是contrecore*/

#define XLP_ALL_FLAGS                                0x0003


长头部结构体如下:

typedef struct XLogLongPageHeaderData                                                                                                      

{

        XLogPageHeaderData std;         /* 头部信息 */

        uint64          xlp_sysid;              /* pg_control中的系统标识符 */

        uint32          xlp_seg_size;     /* 校验位,段的尺寸*/

        uint32          xlp_xlog_blcksz;        /* 校验位,块的尺寸 */

} XLogLongPageHeaderData;

 

        要注意的地方,对于一条很长的xlog日志,当页面没有足够的空间存储时,postgreseql允许把多余的数据存储到下一个页面,即同一条日志写到了两个文件档中。一种数据除外,头部数据是不允许存到两个页面当中的。

        当出现一条日志存放到两个页面时,需要用XLogContRecord来记录该页除了本页面存储的内容外,剩余的存储数据信息:

typedef struct XLogContRecord                                                                                                                       

{

        uint32          xl_rem_len;             /* 记录中剩余信息的总长度*/

} XLogContRecord;

 

        使用xlogdump(之后做一篇详细介绍xlogdump的文章)工具来观察下页面头信息(也可以观察源码xlogdump.c文件的readXLogPage函数),之后详细讲解xlogdump用法:

打印信息如下:

[page:0, xlp_info:3, xlp_tli:1, xlp_pageaddr:0/4C000000] XLP_FIRST_IS_CONTRECORD XLP_LONG_HEADER

 #第一页

函数方法为:

static bool                                                                                                                                                             

readXLogPage(void)

{

         size_t nread = read(logFd, pageBuffer, XLOG_BLCKSZ);

 

         if (nread == XLOG_BLCKSZ)

         {

                   logPageOff += XLOG_BLCKSZ;

                   if (((XLogPageHeader) pageBuffer)->xlp_magic != XLOG_PAGE_MAGIC)

                   {

                            printf("Bogus page magic number %04X at offset %X\n",

                                        ((XLogPageHeader) pageBuffer)->xlp_magic, logPageOff);

                   }

 

                   /*

                    * FIXME: check xlp_magic here.

                    */

                   if (!enable_stats)

                   {

                            printf("[page:%d, xlp_info:%d, xlp_tli:%d, xlp_pageaddr:%X/%X] ",

                                   logPageOff / XLOG_BLCKSZ,

                                   ((XLogPageHeader) pageBuffer)->xlp_info,

                                   ((XLogPageHeader) pageBuffer)->xlp_tli,

                                   ((XLogPageHeader) pageBuffer)->xlp_pageaddr.xlogid,

                                   ((XLogPageHeader) pageBuffer)->xlp_pageaddr.xrecoff);

                           

                            if ( (((XLogPageHeader)pageBuffer)->xlp_info & XLP_FIRST_IS_CONTRECORD) )

                                     printf("XLP_FIRST_IS_CONTRECORD ");

                            if ((((XLogPageHeader)pageBuffer)->xlp_info & XLP_LONG_HEADER) )

                                     printf("XLP_LONG_HEADER ");

#if PG_VERSION_NUM >= 90200

                            if ((((XLogPageHeader)pageBuffer)->xlp_info & XLP_BKP_REMOVABLE) )

                                     printf("XLP_BKP_REMOVABLE ");

#endif

                           

                            printf("\n");

                   }

 

                   return true;

         }

         if (nread != 0)

         {

                   fprintf(stderr, "Partial page of %d bytes ignored\n",

                            (int) nread);

         }

         return false;

}

 

抱歉!评论已关闭.