第 65 章. 通用 WAL 记录
虽然所有内置 WAL 日志模块都有自己的 WAL 记录类型,但还有一种通用 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 记录将包含旧页面图像和新页面图像之间的增量。此增量基于逐字节比较。对于页面内移动数据的情况,这不是非常紧凑的,并且将来可能会得到改进。