Общие записи WAL
Хотя все встроенные модули с WAL-записями имеют свои собственные типы WAL-записей, существует также общий тип WAL-записи, который описывает изменения страниц в общем виде. Это полезно для модулей, предоставляющих пользовательские методы доступа.
По сравнению с пользовательскими менеджерами ресурсов WAL, общий тип WAL-записи проще для реализации расширением и не требует загрузки библиотеки расширения для применения записей.
Примечание:
Общие записи WAL игнорируются во время логического декодирования. Если для вашего расширения требуется логическое декодирование, обратите внимание на пользовательский диспетчер ресурсов WAL.
API для создания общих записей WAL определен в файле 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 должен быть включен образ всей страницы, а не дельта-обновление. Обычно этот флаг устанавливается, если страница новая или была полностью переписана.GenericXLogRegisterBuffer
может быть повторен, если действие, занесенное в WAL-журнал, должно изменить несколько страниц.- Внесите изменения в изображения страниц, полученные в предыдущем шаге.
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 redo приобретает эксклюзивные блокировки буферов в том же порядке, в котором они были зарегистрированы. После повторного выполнения всех изменений блокировки будут освобождены в том же порядке.
- Если
GENERIC_XLOG_FULL_IMAGE
не указан для зарегистрированного буфера, общая запись WAL содержит дельту между старым и новым образами страниц. Эта дельта основана на сравнении байт за байтом. Это не очень компактно для случая перемещения данных внутри страницы и может быть улучшено в будущем.