postgres预写式日志的内核实现详解-wal结构

原创
2018/11/28 16:56
阅读数 3.3K

导读:

    postgres预写式日志的内核实现详解-概述

 

一、Wal文件的page结构    

数据库运行时在数据目录下的pg_wal目录(pg10.0以上版本)下,产生wal日志文件段(如000000010000000000000003),每一个wal段的page的构成如下图。

wal seg组成

PageHeader 

  在wal page的组成中有两种pageheader结构,XLogPageHeaderData和XLogLongPageHeaderData。
    可以看出实际上XLogLongPageHeaderData比XLogPageHeaderData多出三个成员。XLogLongPageHeaderData是用于一个segment的第一个page,xlp_sysid用于记录产生segment的数据库集簇的id,xlp_seg_size和xlp_xlog_blcksz都是固定大小,分别为segment的size和page的size。

remaindata
    这个数据块存储着上一个page的最后一个record没有存完的数据。他的大小是xlp_rem_len。当xlp_rem_len为0时,这个个数据块也就不存在了。

Record
    参照下文中的wal record结构。

不完整的record
    与remaindata相对应,自行理解。

无数据区域
    一个记录里的XlogRecord结构是不能跨页存储的。因此,当剩余的空间不能存储一个XLogRecord结构体时就会被舍弃。

二、Wal记录record的结构

每一个wal记录Record的结构如下图所示。注意蓝框部分是数据描述结构,棕色框部分是实际保存的数据。

wal record结构图

 

1.XLogRecord

XLogRecord是一个wal记录的入口,在解析wal记录时,将从这个结构体开始入手。如下是XlogRecord的结构体定义。

typedef struct XLogRecord
{
	uint32		xl_tot_len;
	TransactionId xl_xid;
	XLogRecPtr	xl_prev;
	uint8		xl_info;
	RmgrId		xl_rmid;
	pg_crc32c	xl_crc;
} XLogRecord;

各成员的意义为:
    xl_tot_len:这个记录的总长度,包括图所有的模块。

    xl_xid:产生此记录的事务ID。
    xl_prev:前一个记录的位置。

    xl_rmid:此成员标志着是何种类型的wal记录,例如RM_XACT_ID为事务相关的记录、    RM_DBASE_ID    为数据库创建删除的记录、RM_HEAP_ID为表数据增删改相关记录。它的取值范围在src/include/access/rmgrlist.h文件中可以看到。

    xl_info:此成员标志着是何种子类型的wal记录。xl_info与xl_rmid结合使用,例如xl_rmid为RM_HEAP_ID,那么xl_info可以为    XLOG_HEAP_INSERT、XLOG_HEAP_DELETE、XLOG_HEAP_UPDATE。

    xl_crc:校验位。

 

2.BLOCK

(1) XLogRecordBlockHeader

在Record结构图中虚线框中的部分可以称为是一个Block的数据,这里主要描述buff相关的数据的结构。

这部分的结构是通过XLogRegisterBuffer()函数注册到wal记录中的(详见《postgres预写式日志的内核实现详解-wal记录写入》)。

typedef struct XLogRecordBlockHeader
{
	uint8		id;	
	uint8		fork_flags;
	uint16		data_length;
} XLogRecordBlockHeader;

各成员的意义为:
     id:一个记录中可以有多个block(MAX: 32),此id是block的序号。
     fork_flags: 本block存储有哪些信息,这个成员决定着①③结构和⑤数据是否存在。
     data_length:决定⑤中存储的数据的长度。

(2) XLogRecordBlockImageHeader

这个结构体存在说明这个wal记录是一个fpw记录,这个结构体是wal记录page数据的

typedef struct XLogRecordBlockImageHeader
{
	uint16		length;
	uint16		hole_offset;
	uint8		bimg_info;

	/*
	 * If BKPIMAGE_HAS_HOLE and BKPIMAGE_IS_COMPRESSED, an
	 * XLogRecordBlockCompressHeader struct follows.
	 */
} XLogRecordBlockImageHeader;

各成员的意义为:
    length:保存的page的总长度(压缩、去零后)。
    hole_offset: 零数据之前的数据的size。
    bimg_info:标志位,这里决定了②结构是否存在

(3) XLogRecordBlockCompressHeader

此结构记录零数据的size

typedef struct XLogRecordBlockCompressHeader
{
	uint16		hole_length;	/* number of bytes in "hole" */
} XLogRecordBlockCompressHeader;

(4) RelFilenode

此结构记录了此block所属的关系。如果当前block与上一个block来源于同一个文件那么fork_flags中就不会有BKPBLOCK_SAME_REL标志位

那么此block中就不会有Relfilenode结构.

typedef struct RelFileNode
{
	Oid			spcNode;		/* tablespace */
	Oid			dbNode;			/* database */
	Oid			relNode;		/* relation */
} RelFileNode;

 

(5) BlockNumber

记录此block记录的page的块号。

 

3.RepOriginId

代码中没有找到描述这个结构的结构体,这里dummy一个来说明这个结构。

typedef struct RepOriginDummy
{
	uint8		id;/*XLR_BLOCK_ID_ORIGIN*/
	RepOriginId	reporiginid;	
}RepOriginDummy;

 

4.XLogRecordDataHeaderLong/XLogRecordDataHeaderShort

此结构XLogRecordDataHeaderLong和XLogRecordDataHeaderShort互斥出现,当⑥的size大于255时使用XLogRecordDataHeaderLong结构

否则使用XLogRecordDataHeaderShort结构

typedef struct XLogRecordDataHeaderShort
{
	uint8		id;	/* XLR_BLOCK_ID_DATA_SHORT */
	uint8		data_length;
}			XLogRecordDataHeaderShort;

typedef struct XLogRecordDataHeaderLong
{
	uint8		id;/* XLR_BLOCK_ID_DATA_LONG */
	/* followed by uint32 data_length, unaligned */
}			XLogRecordDataHeaderLong;

5.buffdata

record的结构图中的绿框部分是buffdata,包含pagedata和tupledata两部分。pgdata数据由XLogRegisterBuffer()函数注册到wal记录

tupledata数据由XLogRegisterBufData()函数注册到wal记录。这里存储了实际的buff数据和变更数据。

比如这是一个insert语句产生的的wal日志,pgdata可能保存了插入的目标page的备份。tupledata可能保存了插入的tuple数据。

 

6. main data

main data部分保存非buff性的数据,通过XLogRegisterData()函数注册的数据,比如wal子类型的特殊结构体、delete和update语句的旧元组或key

 

回到概述页

 

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部