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

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


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


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

postgresql集群方案hot standby初级测试(五)——xlog详细解释record_第1张图片

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)