虽然所有内置的 WAL 记录的模块都有自己的 WAL 记录类型,但也有一个通用的 WAL 记录类型,它以一种通用方式来描述对页面的更改。
在逻辑解码过程中,通用 WAL 记录会被忽略。如果您的扩展需要进行逻辑解码,请考虑使用自定义 WAL 资源管理器。
构建通用 WAL 记录的 API 在 access/generic_xlog.h
中定义,并在 access/transam/generic_xlog.c
中实现。
要使用通用 WAL 记录机制来执行已记录 WAL 数据的更新,请按照以下步骤进行操作
state = GenericXLogStart(relation)
— 开始为给定的关系构造一个通用 WAL 记录。
page = GenericXLogRegisterBuffer(state, buffer, flags)
— 在当前通用 WAL 记录中注册将要修改的缓冲区。此函数返回一个指向缓冲区页面临时副本的指针,在其中进行修改。(请勿直接修改缓冲区内容。)第三个参数是适用于该操作的标志位掩码。当前唯一的此类标志是 GENERIC_XLOG_FULL_IMAGE
,指示 WAL 记录中应包含全页映像而非增量更新。通常,如果页面是新的或者已完全重写,则会设置此标志。如果需记入 WAL 日志的操作需要修改多个页面,则可以重复 GenericXLogRegisterBuffer
。
对在上一步骤中获取的页面映像应用修改。
GenericXLogFinish(state)
— 对缓冲区应用更改并发出通用 WAL 记录。
可以通过调用 GenericXLogAbort(state)
在上述任何步骤之间取消 WAL 记录构造。这将放弃对页面映像副本的所有更改。
使用通用 WAL 记录功能时请注意以下几点
不允许直接修改缓冲区!所有修改都必须在从 GenericXLogRegisterBuffer()
获取的副本中进行。换句话说,生成通用 WAL 记录的代码绝不应为自己调用 BufferGetPage()
。但是,调用者仍负责在适当的时候锁定/解锁和固定/取消固定缓冲区。从 GenericXLogRegisterBuffer()
之前到 GenericXLogFinish()
之后都必须独占锁定每个目标缓冲区。
缓冲区的注册(步骤 2)和页面映像的修改(步骤 3)可以自由混合,即这两个步骤可以按任何顺序重复。请记住,应按重播期间获取锁的顺序注册缓冲区。
为通用 WAL 记录注册的最大缓冲区数量为 MAX_GENERIC_XLOG_PAGES
。如果超出此限制,将引发错误。
通用 WAL 假定要修改的页面具有标准布局,尤其是 pd_lower
和 pd_upper
之间没有有用的数据。
由于您修改的是缓冲区页面的副本,因此 GenericXLogStart()
不启动临界部分。因而,您可以在 GenericXLogStart()
和 GenericXLogFinish()
之间安全地进行内存分配、引发错误等。唯一实际的临界部分存在于 GenericXLogFinish()
内部。在错误退出期间,不必担心调用 GenericXLogAbort()
。
GenericXLogFinish()
负责标记缓冲区为脏数据并设置其 LSN。你不需要明确进行此操作。
对于未记录的关系,所有操作方式相同,只是未发出实际 WAL 记录。因此,你通常不需要对未记录的关系进行任何显式检查。
通用 WAL 重做功能将按照注册顺序获取缓冲区的独占锁。在重做所有改动后,将按相同顺序释放这些锁。
如果未为已注册缓冲区指定GENERIC_XLOG_FULL_IMAGE
,通用 WAL 记录将包含旧页面图像和新页面图像之间的增量。此增量基于逐字节比较。这在页面内移动数据的情况下不是很紧凑,未来可能会得到改进。