支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 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 记录中应包含完整页面映像而不是增量更新。如果页面是新的或已完全重写,通常会设置此标志。GenericXLogRegisterBuffer 如果 WAL 记录的操作需要修改多个页面,则可以重复调用。

  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 记录包含旧页面映像和新页面映像之间的增量。此增量基于逐字节比较。对于在页面内移动数据的情况,这不是非常紧凑,将来可能会改进。

提交更正

如果你发现文档中有任何不正确的地方,与你使用特定功能的经验不符,或需要进一步澄清,请使用此表格报告文档问题。