2025年9月25日: PostgreSQL 18 发布!
支持版本:当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本:devel
不支持的版本:12 / 11 / 10 / 9.6

64.1. 通用 WAL 记录 #

虽然所有内置的 WAL 日志记录模块都有自己的 WAL 记录类型,但还有一个通用的 WAL 记录类型,它以通用方式描述页面的更改。

注意

逻辑解码期间,通用 WAL 记录会被忽略。如果您的扩展需要逻辑解码,请考虑使用自定义 WAL 资源管理器。

用于构造通用 WAL 记录的 API 定义在 access/generic_xlog.h 中,实现在 access/transam/generic_xlog.c 中。

要使用通用 WAL 记录机制执行 WAL 日志记录的数据更新,请执行以下步骤:

  1. state = GenericXLogStart(relation) — 为给定的关系开始构造一个通用 WAL 记录。

  2. page = GenericXLogRegisterBuffer(state, buffer, flags) — 注册要在当前通用 WAL 记录中修改的缓冲区。此函数返回指向缓冲区页面临时副本的指针,修改应在此副本上进行。(请勿直接修改缓冲区内容。)第三个参数是一个适用于该操作的标志位掩码。目前唯一的标志是 GENERIC_XLOG_FULL_IMAGE,它指示 WAL 记录应包含完整页面映像而不是增量更新。通常,如果页面是新的或已完全重写,则会设置此标志。如果 WAL 日志记录的操作需要修改多个页面,则可以重复调用 GenericXLogRegisterBuffer

  3. 在上一阶段获得的页面映像上应用修改。

  4. GenericXLogFinish(state) — 将更改应用于缓冲区并发出通用 WAL 记录。

在上述任何步骤之间,都可以通过调用 GenericXLogAbort(state) 来取消 WAL 记录的构造。这将丢弃对页面映像副本的所有更改。

使用通用 WAL 记录机制时,请注意以下几点:

  • 不允许直接修改缓冲区!所有修改都必须在从 GenericXLogRegisterBuffer() 获取的副本上进行。换句话说,创建通用 WAL 记录的代码本身不应调用 BufferGetPage()。但是,由调用者负责在适当的时候固定/取消固定和锁定/解锁缓冲区。从 GenericXLogRegisterBuffer() 调用之前直到 GenericXLogFinish() 调用之后,必须持有对每个目标缓冲区的独占锁。

  • 缓冲区的注册(步骤 2)和页面映像的修改(步骤 3)可以自由混合,即这两个步骤可以按任何顺序重复。请记住,在重放期间获取锁时,缓冲区应按与获取锁相同的顺序进行注册。

  • 可以为通用 WAL 记录注册的缓冲区的最大数量是 MAX_GENERIC_XLOG_PAGES。如果超出此限制,将抛出错误。

  • 通用 WAL 假定要修改的页面具有标准布局,特别是 pd_lowerpd_upper 之间没有有用的数据。

  • 由于您正在修改缓冲区页面的副本,因此 GenericXLogStart() 不会启动临界区。因此,您可以在 GenericXLogStart()GenericXLogFinish() 之间安全地进行内存分配、错误抛出等操作。唯一的实际临界区存在于 GenericXLogFinish() 内部。在发生错误退出时,也不需要担心调用 GenericXLogAbort()

  • GenericXLogFinish() 负责标记缓冲区为脏并设置其 LSN。您无需显式执行此操作。

  • 对于未记录的(unlogged)关系,所有操作都相同,只是不会发出实际的 WAL 记录。因此,您通常不需要对未记录的关系进行任何显式检查。

  • 通用 WAL 重放函数将按照注册的相同顺序获取缓冲区的独占锁。重放完所有更改后,将按相同顺序释放锁。

  • 如果为注册的缓冲区未指定 GENERIC_XLOG_FULL_IMAGE,则通用 WAL 记录将包含旧页面映像和新页面映像之间的增量。此增量基于逐字节比较。对于页面内移动数据的场景,这不是很紧凑,未来可能会有所改进。

提交更正

如果您在文档中发现任何不正确、与您对特定功能的实际体验不符或需要进一步澄清的内容,请使用此表单来报告文档问题。