Перейти к основному содержимому

Общие записи WAL

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