本节简单介绍了WAL相关的数据结构,包括XLogLongPageHeaderData、XLogPageHeaderData和XLogRecord。
一、数据结构
XLogPageHeaderData
每一个事务日志文件(WAL segment file)的page(大小默认为8K)都有头部数据.
注:每个文件第一个page的头部数据是XLogLongPageHeaderData(详见后续描述),而不是XLogPageHeaderData
//可作为WAL版本信息
#define XLOG_PAGE_MAGIC 0xD098
typedef struct XLogPageHeaderData
{
//WAL版本信息,PG V11.1 --> 0xD98
uint16 xlp_magic;
//标记位(详见下面说明)
uint16 xlp_info;
//page中第一个XLOG Record的TimeLineID,类型为uint32
TimeLineID xlp_tli;
//page的XLOG地址(在事务日志中的偏移),类型为uint64
XLogRecPtr xlp_pageaddr;
//上一页空间不够存储XLOG Record,该Record在本页继续存储占用的空间大小
uint32 xlp_rem_len;
} XLogPageHeaderData;
#define SizeOfXLogShortPHD MAXALIGN(sizeof(XLogPageHeaderData))
typedef XLogPageHeaderData *XLogPageHeader;
XLogLongPageHeaderData
如设置了XLP_LONG_HEADER标记,在page header中存储额外的字段.
(通常在每个事务日志文件也就是segment file的的第一个page中存在).
这些附加的字段用于准确的识别文件。
typedef struct XLogLongPageHeaderData
{
//标准的头部域字段
XLogPageHeaderData std;
//pg_control中的系统标识码
uint64 xlp_sysid;
//交叉检查
uint32 xlp_seg_size;
//交叉检查
uint32 xlp_xlog_blcksz;
} XLogLongPageHeaderData;
#define SizeOfXLogLongPHD MAXALIGN(sizeof(XLogLongPageHeaderData))
//指针
typedef XLogLongPageHeaderData *XLogLongPageHeader;
//如果XLOG Record跨越page边界,在新page header中设置该标志位
#define XLP_FIRST_IS_CONTRECORD 0x0001
//该标志位标明是"long"页头
#define XLP_LONG_HEADER 0x0002
//该标志位标明从该页起始的backup blocks是可选的(不一定存在)
#define XLP_BKP_REMOVABLE 0x0004
//xlp_info中所有定义的标志位(用于page header的有效性检查)
#define XLP_ALL_FLAGS 0x0007
#define XLogPageHeaderSize(hdr) \
(((hdr)->xlp_info & XLP_LONG_HEADER) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD)
XLogRecord
事务日志文件由N个的XLog Record组成,逻辑上对应XLOG Record这一概念的数据结构是XLogRecord.
XLOG Record的整体布局如下:
头部数据(固定大小的XLogRecord结构体)
XLogRecordBlockHeader 结构体
XLogRecordBlockHeader 结构体
...
XLogRecordDataHeader[Short|Long] 结构体
block data
block data
...
main data
XLOG Record按存储的数据内容来划分,大体可以分为三类:
1.Record for backup block:存储full-write-page的block,这种类型Record的目的是为了解决page部分写的问题;
2.Record for (tuple)data block:在full-write-page后,相应的page中的tuple变更,使用这种类型的Record记录;
3.Record for Checkpoint:在checkpoint发生时,在事务日志文件中记录checkpoint信息(其中包括Redo point).
XLOG Record的详细解析后续会解析,这里暂且不提
typedef struct XLogRecord
{
//record的大小
uint32 xl_tot_len;
//xact id
TransactionId xl_xid;
//指向log中的前一条记录
XLogRecPtr xl_prev;
//标识位,详见下面的说明
uint8 xl_info;
//该记录的资源管理器
RmgrId xl_rmid;
//2个字节的crc校验位,初始化为0
pg_crc32c xl_crc;
//接下来是XLogRecordBlockHeaders和XLogRecordDataHeader
} XLogRecord;
//宏定义:XLogRecord大小
#define SizeOfXLogRecord (offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c))
#define XLR_INFO_MASK 0x0F
#define XLR_RMGR_INFO_MASK 0xF0
#define XLR_SPECIAL_REL_UPDATE 0x01
#define XLR_CHECK_CONSISTENCY 0x02
typedef struct XLogRecordBlockHeader
{
//块引用ID
uint8 id;
//在关系中使用的fork和flags
uint8 fork_flags;
//payload字节大小
uint16 data_length;
//如BKPBLOCK_HAS_IMAGE,后续为XLogRecordBlockImageHeader结构体
//如BKPBLOCK_SAME_REL没有设置,则为RelFileNode
//后续为BlockNumber
} XLogRecordBlockHeader;
#define SizeOfXLogRecordBlockHeader (offsetof(XLogRecordBlockHeader, data_length) + sizeof(uint16))
typedef struct XLogRecordBlockImageHeader
{
uint16 length;
uint16 hole_offset;
uint8 bimg_info;
} XLogRecordBlockImageHeader;
#define SizeOfXLogRecordBlockImageHeader \
(offsetof(XLogRecordBlockImageHeader, bimg_info) + sizeof(uint8))
//------------ bimg_info标记位
//存在"hole"
#define BKPIMAGE_HAS_HOLE 0x01
//压缩存储
#define BKPIMAGE_IS_COMPRESSED 0x02
//在回放时,page image需要恢复
#define BKPIMAGE_APPLY 0x04
typedef struct XLogRecordBlockCompressHeader
{
//"hole"的大小
uint16 hole_length;
} XLogRecordBlockCompressHeader;
#define SizeOfXLogRecordBlockCompressHeader \
sizeof(XLogRecordBlockCompressHeader)
#define MaxSizeOfXLogRecordBlockHeader \
(SizeOfXLogRecordBlockHeader + \
SizeOfXLogRecordBlockImageHeader + \
SizeOfXLogRecordBlockCompressHeader + \
sizeof(RelFileNode) + \
sizeof(BlockNumber))
#define BKPBLOCK_FORK_MASK 0x0F
#define BKPBLOCK_FLAG_MASK 0xF0
//块数据是XLogRecordBlockImage
#define BKPBLOCK_HAS_IMAGE 0x10
#define BKPBLOCK_HAS_DATA 0x20
//重做时重新初始化page
#define BKPBLOCK_WILL_INIT 0x40
//重做时重新初始化page,但会省略RelFileNode
#define BKPBLOCK_SAME_REL 0x80
typedef struct XLogRecordDataHeaderShort
{
uint8 id;
uint8 data_length;
} XLogRecordDataHeaderShort;
#define SizeOfXLogRecordDataHeaderShort (sizeof(uint8) * 2)
typedef struct XLogRecordDataHeaderLong
{
uint8 id;
//接下来是无符号32位整型的data_length(未对齐)
} XLogRecordDataHeaderLong;
#define SizeOfXLogRecordDataHeaderLong (sizeof(uint8) + sizeof(uint32))
#define XLR_MAX_BLOCK_ID 32
#define XLR_BLOCK_ID_DATA_SHORT 255
#define XLR_BLOCK_ID_DATA_LONG 254
#define XLR_BLOCK_ID_ORIGIN 253
#endif
这些数据结构在WAL segment file文件中如何布局,请参见后续的章节
二、参考资料
Write Ahead Logging — WAL
PostgreSQL 源码解读(4)- 插入数据#3(heap_insert)
PG Source Code
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
软考中级精品资料免费领
- 历年真题答案解析
- 备考技巧名师总结
- 高频考点精准押题
- 资料下载
- 历年真题
193.9 KB下载数265
191.63 KB下载数245
143.91 KB下载数1148
183.71 KB下载数642
644.84 KB下载数2756
相关文章
发现更多好内容- JAVA 中如何运用 QT 来开发 GUI?(JAVA中怎么使用QT开发GUI)
- 如何在 MySQL 中优化插入大量数据的操作?(mysql insert大量数据时如何优化)
- 如何高效升级Redis客户端
- Java 中如何获取内存地址中的值?(java如何获取内存地址中的值)
- 在 Java 中,showdialog 的具体用法究竟是什么?(java中showdialog的用法是什么)
- 如何在 Java 中应用 Hyperscan 以及其具体场景有哪些?(Hyperscan在Java中的应用场景)
- 如何在 Java 中求二维数组的最大值?(java怎么求二维数组的最大值)
- Java 中 invoke 方法的作用究竟是什么?(java invoke方法的作用是什么)
- Java 代理模式常见的应用场景有哪些?(java代理模式的应用场景是什么)
- 如何在 Java 中求平均值?(java怎么求平均值)