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

  • Если для регистрируемого буфера не задаётся GENERIC_XLOG_FULL_IMAGE, унифицированная запись WAL содержит различие между старым и новым образом страницы, которое вычисляется при побайтовом сравнении. Результат оказывается не очень компактным при перемещении данных в странице, но это может быть доработано в будущем.