Типовые записи WAL

Хотя все встроенные модули, протоколирующие в WAL, поддерживают собственные типы записей WAL, существует также типовой вид записи WAL, описывающий изменения страниц типовым образом. Это полезно для расширений, предоставляющих нестандартные методы доступа, поскольку они не могут зарегистрировать свои подпрограммы воспроизведения WAL.

API для построения типовых записей WAL определяется в 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.

Построение записи WAL можно отменить на любом из вышеперечисленных этапов путем вызова GenericXLogAbort(state). Это приведет к отмене всех изменений в копиях образа страницы.

Пожалуйста, при использовании типового средства записи 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 содержит разницу между старым и новым образами страниц. Эта разница основывается на побайтовом сравнении. Результат будет не очень компактным в случае перемещения данных в пределах страницы, однако это может быть улучшено в будущем.