数据库 Xlog 知识整理与代码走读

XLOG

一些概念

基本概念

XLOG(也称为WAL日志)是预写日志(Write-Ahead Logging)的一部分。XLOG是一种持久化的、顺序记录的日志,用于记录数据库系统中对数据进行的更改。

具体来说,XLOG用于确保数据库的持久性和一致性。其工作原理如下:

  1. 当对数据库中的数据进行修改时,首先将数据变更写入XLOG中。
  2. 接着,将数据变更写入实际的数据文件。
  3. 事务提交时,不要求发生变化的数据页面罗盘,但必须要求本事务的xlog落盘。

在数据库崩溃或服务器故障时,可以使用XLOG中的信息来恢复数据,确保数据库完整性。因此,XLOG是数据库事务持久性的关键组成部分,它确保了即使在出现意外情况时,数据库也能够在重新启动后恢复到一个一致的状态。

总而言之,XLOG(WAL日志)是PostgreSQL中用于持久化记录数据更改的机制,它是数据库性能、一致性和可靠性的重要保障。

文件管理结构

XLOG日志一条一条的顺序写入XLOG文件。文件是以固定大小的段(segment)的方式组织的。每个 XLOG 段的大小是固定的,通常是 16MB。XLOG 文件是循环使用的,一旦填满一个段,它将被标记为已用,并且新的 XLOG 记录将写入下一个可用的 XLOG 段中。

XLOG 段的组织方式通常是这样的:

  1. XLOG 文件名格式:XLOG 文件的命名格式通常是 XLOG+数字+段位置,例如,XLOG 文件名可能是 XLOG000000010000001D,其中 000000010000001D 是 XLOG 段的位置。

  2. XLOG 文件目录结构:XLOG 文件通常存储在数据库的数据目录下的 pg_xlog 子目录中。每个数据库都有自己的 pg_xlog 目录。

  3. XLOG 段的循环使用:一旦一个 XLOG 段被写满,新的 XLOG 记录将被写入下一个可用的 XLOG 段中。当所有 XLOG 段都被写满后,旧的 XLOG 段会被标记为可重用。

  4. 检查点:定期进行检查点操作来确保部分 XLOG 段中的数据已经写入数据文件中,这样可以释放已经写入数据文件中的 XLOG 段。检查点操作也有助于限制重做日志(WAL)的增长速度。

总的来说,XLOG 文件以固定大小的段的形式组织,通过循环使用这些段,确保了持久化记录数据库更改的机制。这个机制保证了即使在数据库崩溃或服务器故障情况下,都能够进行数据恢复和一致性保障。

16M文件1:
XLog1
XLog2
XLog3
...

16M文件2:
XLog888
XLog889
XLog890
...


LSN(Log Sequence Number)

日志序列号,是一种用于标识事务日志中位置的特殊序号,主要用于在数据库恢复过程中跟踪和管理 xlog 日志文件的位置。

因为XLOG是一条条顺序写入文件的,那么每条xlog的起始位置,也就是在所有xlog文件中的偏移量,就是这条xlog的LSN,所以不难看出 LSN 是一个递增的数字。

对于xlog来说,lsn是它的位置,也是唯一标识;对于页面来说,LSN相当于页面的版本号。

XLOG结构


{XLogRecord} + {XLogRecordBlockHeader}*N + {(Short/Long)XLogRecordDataHeader} + {Block data}*N + {main data}

共5部分,其中第二或四部分不涉及的话可能没有。

数据结构与接口

关键数据结构

struct XLogRecord: 一条XLog

{
    uint32 xl_tot_len;  xlog的总长度
    xl_term;
    TransactionId xl_xid; 事务号
    XLogRecPtr xl_prev;   前边那条xlog的lsn
    RmgrId xl_rmid;      xlog的类型
    ...
    xl_crc;  CRC校验码
}
    这只是个xlog的头部,在这个后面物理空间上会紧跟这剩余的xlog内容

struct XLogRecData: 一条Xlog中的某种数据的容器。

struct XLogRecData {
    struct XLogRecData* next;
    char* data;
    uint32 len;
    Buffer buffer;
}

是一个通用的容器,可以存放很多东西。例如xlog本身的一些元信息、具体的某段数据(如insert的某行元组)等。

struct registered_buffer: xlog所操作的页面的注册信息

一条xlog里面相关的页面操作,这个结构用于存放页面的相关元信息,如页面位置、lastlsn。

其中还有一个链表,rdata,存放这个页面上的操作的具体数据,如insert的元组等。一个xlog上可能会有多个操作,例如update,可能会delete+insert元组在同一个页面等。

knl_t_xlog_context: xlog上下文,有很多xlog的相关数据结构。

    
    
    // 一个数组,构造xlog的时候使用,用于存放xlog所操作的页面的很多元信息。
    registered_buffer* registered_buffers;
    int max_registered_buffers;
    int max_registered_block_id;
    
    
    // 一个单链表,构造xlog的时候使用,用于存放xlog内的数据内容。
    XLogRecData* mainrdata_header;
    XLogRecData* mainrdata_last;
    uint32 mainrdata_len;
    
    
    // 一个数组,用于存放registered_buffers的页面数据。物理上是一个数组,逻辑上是好多链表,不同的链表归不同的registered_buffers。
    XLogRecData* rdatas;
    int max_rdatas;
    int num_rdatas;


关键接口

XlogBeginInsert():

做Xlog插入的准备工作,主要是检查状态、初始化一些变量等。

XlogRegisterData(char *data, int len)

创建一个XLogRecData,注册到链表manrdata之中。

XlogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags, TdeInfo* tdeinfo):

根据buffer构造struct registered_buffer,注册到registered_buffers数组。

其中block_id是registered_buffers数组的下标。

这里的数据,主要是页面的元信息,例如lsn等。

XlogRegisterBufData(uint8 block_id, Buffer buffer, uint8 flags, TdeInfo* tdeinfo):

根据buffer构造struct registered_buffer,注册到rdatas数组。

这里的数据指的就是具体的元组了。

XLogInsert():

根据前面接口注册的各种信息,构造出一条xlog,写入xlog缓冲区,返回lsn。

代码流程

    
    检查些有的没的
    
    GetFullPageWriteInfo()
    
    # 将之前注册的所有信息(链表manrdata、registered_buffers数组等),整理成一个链表
    XlogRecData* rdt = XLogRecordAssemble()
    
    
    # 插入xlog到缓冲区,并获取LSN
    EndPos = XLogInsertRecord();
    
    # 返回LSN
    return EndPos;
  • 29
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值