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

63.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。您无需显式执行此操作。

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

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

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

提交更正

如果您在文档中发现任何不正确的内容,不符合您对特定功能的体验,或者需要进一步说明,请使用 此表格 报告文档问题。