首先写入的是XLOG的头(XLogPageHeader)。这个page_magic也可以用来验证是否是 一个page的开头 每个XLogSegment的第一个page头会写入XLogLongPageHeaderData,结构体如下:结果如下:这个page的前40个字节就是XLogLongPageHeaderData。写入完之后整个的XLOG_SEGMENT的结构如下图所示:但是 有一个问题 就是...
解析XLog:使用python通过外部解析XLog
初衷就是想深入xlog内部,想具体看一看wal内部到底存储着什么内容,为什么可以通过wal日志恢复所有的数据信息,包括为什么他可以实现主从复制等一系列操作
最终目的:拆解wal日志
我们可以使用pg_waldump查看wal信息
初始化XLOG的函数入口为BootStrapXLOG
这个函数只会在初始化的时候调用一次,用来创建控制文件和初始化XLOG segment。
我们先看看第一个XLOG文件名称生成:
所以最大的XLOG文件名称为:00000001FFFFFFFF000000FF,而不是理论上的00000001FFFFFFFFFFFFFFFF,因为uint64 % 256 最大是FF。
初始化第一个timelineID = 1
还是在xlog.c这个文件中说明创建这个文件之间会先创建一个临时文件,
pg_wal/xlogtemp.xxxxxxx("xlogtemp."加个当前进程PID),避免其他process来搞事情,然后循环写入每次写入XLOG_BLOCKSZ个字节
写完后文件大小为16M
刚才创建的文件其实是一个空文件,随后通过durable_link_or_rename进行rename。
到这里,XLOG就创建完成了,不过这个文件还是空空如也
首先写入的是XLOG的头(XLogPageHeader)。
这个page_magic也可以用来验证是否是 一个page的开头
每个XLogSegment的第一个page头会写入XLogLongPageHeaderData,结构体如下:
结果如下:
这个page的前40个字节就是XLogLongPageHeaderData。写入完之后整个的XLOG_SEGMENT的结构如下图所示:
但是 有一个问题 就是为什么是40B?这里先按下不表,后面解析的时候会遇到问题。
日志之间有链接关系,xl_prev指向上一条日志的起始位置,下一条日志的位置用xl_tot_len可以找到,日志之间形成“双向链表”。
typedef struct XLogRecord{
【日记长度】
uint32xl_tot_len;/* total len of entire record */
【事务ID】
TransactionId xl_xid;/* xact id */
【上一条日志的LSN】
XLogRecPtrxl_prev;/* ptr to previous record in log */
【产生这个记录的动作】
uint8xl_info;/* flag bits, see below */
【日志记录对应的资源管理器】
RmgrIdxl_rmid;/* resource manager for this record */
/* 2 bytes of padding here, initialize to zero */
pg_crc32cxl_crc;/* CRC for this record */
/* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */
【日志的数据信息】} XLogRecord;
xl_info低4位保存flag信息,高4位保存日志动作信息。
资源管理器的定义如下所示:
typedef struct RmgrData {
const char *rm_name; // 资源名称
void(*rm_redo) (XLogReaderState *record); // 重做函数
void(*rm_desc) (StringInfo buf, XLogReaderState *record); // 负责解析对应资源事务日志
const char *(*rm_identify) (uint8 info); // 解析xlog记录中的Info字段
void(*rm_startup) (void); // 启动时的初始化工作
void(*rm_cleanup) (void); // 结束时的清理工作
void(*rm_mask) (char *pagedata, BlockNumber blkno); // 在对页面做一致性检查前,是否需要对页面的某些部分做掩码} RmgrData;
据xlog中的xl_rmid调用资源管理器中不同资源的rm_redo回放函数进行回放。
在 PostgreSQL 内核中,rmgrlist.h 文件定义了各种类型的 rmgr(record manager),每个 rmgr 对应一个不同的数据库操作。这些 rmgr 在事务日志(XLog)中起着重要作用,用于记录不同类型的数据库操作,以便在之后的恢复过程中重做(redo)或撤销(undo)这些操作。
heap_mask 函数是 PostgreSQL 内核中用于在执行一致性检查之前对堆页(heap page)进行掩码处理的函数。在执行恢复操作时,数据库会读取 XLog 记录中的内容,并应用到对应的数据页上。为了保证恢复的正确性,必须对数据页进行一致性检查,而 heap_mask 就是用于在执行这些检查之前,对数据页进行掩码处理,从而屏蔽掉不应该参与一致性检查的部分。
以下是 heap_mask 函数的主要功能:
在实现WAL一致性检查功能时,只有涉及数据表的RMGR才需要使用Mask Function,而对于其他类型的RMGR,由于其重做操作本身已经保证了数据的正确性,因此不需要添加Mask Function。
通过区分需要Mask的RMGR和不需要Mask的RMGR,可以在WAL一致性检查过程中准确地找出可能导致数据不一致的地方,并对数据库的一致性进行严格的验证。这样,复制过程中出现的潜在问题可以及早被检测出来,并及时处理,保障数据库系统的可靠性和稳定性。
结果展示
解析wal日志
为什么XLogLongPageHeaderData 一搜都是40B? 仔细阅读源码,发现问题
在XLogPageHeaderData底下出现了这个定义
这一块定义了XLogPageHeaderData的长度
分析一下 MAXALIGN---其实读英文名就可以知道 他的意思是对齐 最大
这个上面的内容就是 PG内部做了一个对齐宏,类似于 只要是PG内部的东西 基本上就按照这个对齐宏走
其中 MAXIMUM_ALIGNOF 这个是获得当前编译器中占最大位的基本类型,比如long long类型
取得的long long类型的大小为8BYTE,所以在这个宏定义当中,MAXIMUM_ALIGNOF=8
MAXALIGN 的作用其实就是为了使sizeof( struct )向上对齐,成为8的倍数的大小
思考为什么会有rem等问题,如果这个操作的tuple内容很多怎么办,或者当前record没有填满怎么办
他会根据逻辑地址算出物理插入地址,也就是说,物理地址并不会像逻辑地址那样整齐排列。
拿到对应的info后,应该怎么判断它属于什么操作,增删改查?
读取wal2024-09-05