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

上一篇文章讲了下xlog的头部,今天详细讲解下record部分,希望这两篇文章对研究postgresql的xlog的同学有所帮助:


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


首先看下XLOG日志记录结构:


XLogRecord记录了XLOG的相关控制信息,数据结构如下:

typedef struct XLogRecord

{

        pg_crc32        xl_crc;                 /* 本条记录的CRC校验码 */                                                                                                                                                       

        XLogRecPtr      xl_prev;                /* 日志的前一条记录 */

        TransactionId xl_xid;                     /* 事务ID */

        uint32          xl_tot_len;             /* 整条记录的总长度*/

        uint32          xl_len;                 /* 组员管理器的数据长度*/

        uint8           xl_info;                /* 信息标志位 */

        RmgrId          xl_rmid;         /* 资源管理器IDtypedef uint8 RmgrId;*/

} XLogRecord;


        其中,资源管理器ID主要用于日志系统中,数据库系统把各种需要记录日志的数据分类,分配给他们对应的资源管理号,系统在回复或者读取日志记录时,能够很方便地知道该日志记录的元数据属于哪一类,结合信息标志位(xl_info)信息,就能知道数据库对元数据做的是那种操作。共有16中资源(有几项还不清楚是做什么用的):

#define RM_XLOG_ID         0       该条日志记录的是一个检查点信息。                                                                                                                                         

#define RM_XACT_ID           1       该条日志记录的是一个事物的提交或者终止信息

#define RM_SMGR_ID          2      

#define RM_CLOG_ID          3       CLOG中某一页的初始化

#define RM_DBASE_ID          4

#define RM_TBLSPC_ID          5

#define RM_MULTIXACT_ID       6

#define RM_RELMAP_ID         7

#define RM_STANDBY_ID        8

#define RM_HEAP2_ID          9

#define RM_HEAP_ID         10       该条日志记录的是对队中元组进行修改的信息

#define RM_BTREE_ID        11       该条日志记录的是对BTree进行修改

#define RM_HASH_ID        12

#define RM_GIN_ID          13

#define RM_GIST_ID         14

#define RM_SEQ_ID          15


        信息标志位(xl_info)的高四位由资源管理器使用,表示该日志是哪种类型的日志,低四位表示对应的块是否需要备份,对于高四位,信息有如下几种:

/* include/access/xact.h

 * XLOG allows to store some information in high 4 bits of log

 * record xl_info field

 */

#define XLOG_XACT_COMMIT               0x00          //事务提交

#define XLOG_XACT_PREPARE               0x10         //预备

#define XLOG_XACT_ABORT                 0x20         //事务取消

#define XLOG_XACT_COMMIT_PREPARED      0x30         //准备提交事务

#define XLOG_XACT_ABORT_PREPARED        0x40         //准备取消事务

#define XLOG_XACT_ASSIGNMENT            0x50        //不详。。。(之后补充)

 

 

/*include/access/htup.h

 * WAL record definitions for heapam.c's WAL operations

 * XLOG allows to store some information in high 4 bitsof log

 * record xl_info field.  We use 3 for opcode and one for init bit.

 */

#define XLOG_HEAP_INSERT        0x00            //插入元组日志

#define XLOG_HEAP_DELETE       0x10            //删除元组日志

#define XLOG_HEAP_UPDATE       0x20            //更新元组日志

 

细心的同学会发现,下面的元组操作和上面的事务操作的编码(0x00)重复了,不要忘记之前我们说过,要通过xl_rmid字段来判断属于何种操作:先判断属于那种操作,在做具体的操作内容。


低四位中只用了位,具体如下(可以看到最后一位没有用到):

/*include/access/xlog.h

 * If we backed up any disk blocks with the XLOG record, we use flag bits in                                                                                                                                                                         

 * xl_info to signal it.  We support backup of up to 3 disk blocks per XLOG

 * record.

 */

#define XLR_BKP_BLOCK_MASK              0x0E    /* all info bits used for bkp blocks */

#define XLR_MAX_BKP_BLOCKS              3

#define XLR_SET_BKP_BLOCK(iblk) (0x08 >> (iblk))

#define XLR_BKP_BLOCK_1                 XLR_SET_BKP_BLOCK(0)    /* 0x08 */

#define XLR_BKP_BLOCK_2                 XLR_SET_BKP_BLOCK(1)    /* 0x04 */

#define XLR_BKP_BLOCK_3                 XLR_SET_BKP_BLOCK(2)    /* 0x02 */

 

日志记录数据信息:

        rmgr data 数据被XLogInsert()函数写入,有一个或多个XlogRecData数据结构组成,当有多个XLogRecData结构体时有两种情况:1.源数据没有在内存上物理相邻;2.数据在多个缓冲区中被指定。

 

       如果buffer有效,那么XLOG将会检查buffer是否必须备份(即,是否该buffer自最后一次checkpoint以来,第一次被更改)。如果是这样,那么整个页面内容会被附加到XLOG日志中,同时,XLOG在标志位xl_info中设置XLR_BKP_BLOCK_X位。注:buffer备份后,我们不能够通过XLogRecData结构体插入数据到XLOG记录中,因为我们假定他已经在buffer中了,因此rmgr的redo操作必须注意XLR_BKP_BLOCK_X的值,以便指导XLOG记录中到底存的是什么。

 

如果buffer有效,调用者必须设置buffer_std(缓冲区存储标准),来表明页面是否用标准pd_lower/pd_upper头字段。

 

日志记录中的数据信息存储在结构XlogRecData中(结构体如下):

typedef struct XLogRecData

{

        char       *data;                       /* 资源管理器数据 */

        uint32          len;                    /* 资源管理器数据的长度 */                                                                                                                                                             

        Buffer          buffer;                 /* 该数据涉及的缓冲区*/

        bool            buffer_std;             /* 缓冲区存储标准 */

        struct XLogRecData *next;                /* 下一个节点指针 */

} XLogRecData;


        这里保存了所有操作信息,在阅读了xlogdump源码之后发现,读取xlog记录不需要XLogRecData结构体,例如读取插入操作时,只需要调用xl_heap_insert结构体就可以取出数据。

 

        例如执行了一次insert,用xlogdump可以读出下面的代码(同样的updata、delete以及事务操作commit和abort都在改数据内):

INSERT: 2 row(s) found in the table `t_user'.           //有两个字段在表“t_user”中

INSERT: column 0, name userid, type 1043, value '14541'//包括字段名,字段类型,字段的值都会在数据中取出,如果想了解具体细节可以看xlogdump的源码。

INSERT: column 1, name name, type 1043, value 'lengzijian'

 

XLOG记录中的备份数据块的头部信息保存在BkpBlock中,数据结构如下:

typedef struct BkpBlock

{

        RelFileNode node;                       /* 表节点*/                                                                                                                                                                                                 

        ForkNumber      fork;                   /* 关系分支*/

        BlockNumber block;                      /* 块数 */

        uint16          hole_offset;             /* "hole"偏移值 */

        uint16          hole_length;             /* "hole"长度 */

        /* 实际的块数据在结构体之后 */

} BkpBlock;

 

在用xlogdump工具时,发现一个问题,就是更新或插入时,有时不能够打印出statements,例如:

lengzijian-----------record->xl_len[21]/SizeOfHeapUpdate:[28]/SizeOfHeapHeader:[5]

//这里我打印出他的判断信息,由于(21 – 28 – 5)的无符号型大于MaxHeapTupleSize

//所以退出,没有打印出statements.

[cur:0/4C6F0960, xid:5215584, rmid:10(Heap), len/tot_len:21/2781, info:9, prev:0/4C6F0910] insert: s/d/r:pg_default/lengzijian/t_user blk/off:758/61 header: none

 

[cur:0/4C6F0960, xid:5215584, rmid:10(Heap), len/tot_len:21/2781, info:9, prev:0/4C6F0910] bkpblock[1]: s/d/r:pg_default/lengzijian/t_user blk:758 hole_off/len:268/5484

//根据如上分析:是由于已经把数据备份到bkpblock[1]中,通过观察日志也可以看到,在之后,xlogdumpbkpblock也打印出来,说明xl_info的后低四位被设置了。

 

下一篇讲解xlogdump工具的使用和部分源码分析。


你可能感兴趣的:(数据库,postgresql,集群,源代码)