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