Пример плагина вывода можно найти в
contrib/test_decoding
подкаталоге дерева исходных кодов PostgreSQL.
Плагин вывода загружается путем динамической загрузки разделяемой библиотеки, базовое имя которой совпадает с именем плагина вывода. Для поиска библиотеки используется стандартный путь поиска системных библиотек. Чтобы предоставить необходимые функции обратного вызова
плагина вывода и подтвердить, что библиотека действительно является плагином
вывода, она должна содержать функцию с именем
_PG_output_plugin_init
. В данную функцию передается структура, которую необходимо заполнить указателями на функции обратного вызова для соответствующих действий.
typedef struct OutputPluginCallbacks
{
LogicalDecodeStartupCB startup_cb;
LogicalDecodeBeginCB begin_cb;
LogicalDecodeChangeCB change_cb;
LogicalDecodeTruncateCB truncate_cb;
LogicalDecodeCommitCB commit_cb;
LogicalDecodeMessageCB message_cb;
LogicalDecodeFilterByOriginCB filter_by_origin_cb;
LogicalDecodeShutdownCB shutdown_cb;
LogicalDecodeFilterPrepareCB filter_prepare_cb;
LogicalDecodeBeginPrepareCB begin_prepare_cb;
LogicalDecodePrepareCB prepare_cb;
LogicalDecodeCommitPreparedCB commit_prepared_cb;
LogicalDecodeRollbackPreparedCB rollback_prepared_cb;
LogicalDecodeStreamStartCB stream_start_cb;
LogicalDecodeStreamStopCB stream_stop_cb;
LogicalDecodeStreamAbortCB stream_abort_cb;
LogicalDecodeStreamPrepareCB stream_prepare_cb;
LogicalDecodeStreamCommitCB stream_commit_cb;
LogicalDecodeStreamChangeCB stream_change_cb;
LogicalDecodeStreamMessageCB stream_message_cb;
LogicalDecodeStreamTruncateCB stream_truncate_cb;
} OutputPluginCallbacks;
typedef void (*LogicalOutputPluginInit) (struct OutputPluginCallbacks *cb);
Функции обратного вызова
begin_cb
,
change_cb
и
commit_cb
являются обязательными,
в то время как
startup_cb
,
truncate_cb
,
message_cb
,
filter_by_origin_cb
,
и
shutdown_cb
являются необязательными.
Если функция
truncate_cb
не задана, но при этом команда
TRUNCATE
должна быть декодирована, данное действие будет проигнорировано.
Плагин вывода может также определять функции для поддержки потоковой передачи больших выполняющихся транзакций. Функции
stream_start_cb
,
stream_stop_cb
,
stream_abort_cb
,
stream_commit_cb
, и
stream_change_cb
являются обязательными, тогда как
stream_message_cb
и
stream_truncate_cb
являются необязательными. Функция
stream_prepare_cb
также требуется, если плагин вывода поддерживает двухфазные фиксации.
Плагин вывода может также определять функции для поддержки двухфазных фиксаций,
что позволяет декодировать действия при выполнении команды
PREPARE TRANSACTION
.
Функция
begin_prepare_cb
,
prepare_cb
,
commit_prepared_cb
и
rollback_prepared_cb
функции обратного вызова являются обязательными, в то время как
filter_prepare_cb
является необязательным. Этот
stream_prepare_cb
также является обязательной, если плагин вывода
поддерживает потоковую передачу больших незавершенных транзакций.
Для декодирования, форматирования и вывода изменений плагины вывода могут использовать большую часть стандартной инфраструктуры серверной части, включая вызов функций вывода. Доступ только для чтения к отношениям разрешен при условии, что осуществляется доступ только к тем отношениям, которые были созданы
initdb
в
pg_catalog
схеме или были помечены как пользовательские
таблицы каталога с помощью
ALTER TABLE user_catalog_table SET (user_catalog_table = true); CREATE TABLE another_catalog_table(data text) WITH (user_catalog_table = true);
Обратите внимание, что доступ к пользовательским таблицам каталога или обычным системным таблицам каталога в плагинах вывода должен осуществляться только через
systable_*
API сканирования. Доступ через
heap_*
API сканирования приведет к ошибке. Кроме того, любые действия, приводящие к назначению идентификатора транзакции, запрещены. Это, помимо прочего, включает запись в таблицы, выполнение DDL-запросов и вызов функции
pg_current_xact_id()
.
Функции обратного вызова плагина вывода могут передавать данные потребителю практически в любых форматах. Для некоторых сценариев использования, таких как просмотр изменений с помощью SQL, возврат данных в типе, предназначенном для произвольных данных (например,
bytea
), оказывается
неудобным. Если плагин вывода генерирует только текстовые данные в кодировке
сервера, он может сообщить об этом,
установив параметр
OutputPluginOptions.output_type
в значение
OUTPUT_PLUGIN_TEXTUAL_OUTPUT
вместо
значения
OUTPUT_PLUGIN_BINARY_OUTPUT
в
функции обратного вызова
startup
. В этом случае все данные должны быть представлены в кодировке сервера,
чтобы значение типа
текст
datum могло их содержать. Это проверяется в сборках с поддержкой утверждений (assertions).
Плагин вывода получает уведомления о происходящих изменениях через различные функции обратного вызова, которые он должен предоставить.
Параллельные транзакции декодируются в порядке их фиксации, при этом в интервале между
begin
и
commit
функции обратного вызова. Транзакции, которые были отменены явно или неявно, никогда не декодируются. Успешные точки сохранения (savepoints) включаются в состав содержащей их транзакции в том порядке, в котором они выполнялись. Транзакция, подготовленная для двухфазной фиксации с помощью
PREPARE TRANSACTION
, также будет декодирована, если предоставлены функции обратного вызова плагина вывода, необходимые для её декодирования. Возможна ситуация, когда текущая подготовленная транзакция, находящаяся в процессе декодирования, прерывается параллельно с помощью команды
ROLLBACK PREPARED
command. В этом случае логическое декодирование этой транзакции также будет прервано. Все изменения такой транзакции пропускаются сразу после обнаружения отмены и вызывается
prepare_cb
callback-функция. Таким образом, даже при параллельной отмене плагину вывода передается достаточно информации для корректной обработки
ROLLBACK PREPARED
после того, как это будет декодировано.
Декодированы будут только те транзакции, которые были успешно сброшены на диск. Это может привести к
COMMIT
не декодируются немедленно в непосредственно следующем вызове
pg_logical_slot_get_changes()
когда
synchronous_commit
установлен
в значение
off
.
Необязательная
startup_cb
функция обратного вызова вызывается всякий раз, когда создается слот репликации или запрашивается потоковая передача изменений, независимо от количества изменений, готовых к выводу.
typedef void (*LogicalDecodeStartupCB) (struct LogicalDecodingContext *ctx,
OutputPluginOptions *options,
bool is_init);
Параметр
is_init
будет иметь значение true при создании слота репликации и false в противном случае.
options
указывает на структуру параметров, которые могут быть заданы плагинами вывода:
typedef struct OutputPluginOptions
{
OutputPluginOutputType output_type;
bool receive_rewrites;
} OutputPluginOptions;
output_type
должно быть установлено либо в значение
OUTPUT_PLUGIN_TEXTUAL_OUTPUT
либо в
OUTPUT_PLUGIN_BINARY_OUTPUT
. См. также
Раздел 5.12.6.3
.
Если параметр
receive_rewrites
имеет значение true, плагин вывода также будет вызываться для изменений, вызванных перезаписью кучи (heap rewrites) при выполнении определенных DDL-операций. Эти изменения важны для плагинов, поддерживающих репликацию DDL, однако они требуют специальной обработки.
Функция обратного вызова при запуске должна проверять параметры, содержащиеся в
ctx->output_plugin_options
. Если плагину вывода
требуется сохранять состояние, он может
использовать
ctx->output_plugin_private
для его хранения.
Необязательная
shutdown_cb
функция обратного вызова вызывается при прекращении использования ранее активного слота репликации и может применяться для освобождения внутренних ресурсов плагина вывода. Сам слот при этом не обязательно удаляется — может быть просто остановлена потоковая передача.
typedef void (*LogicalDecodeShutdownCB) (struct LogicalDecodingContext *ctx);
Обязательная
begin_cb
функция обратного вызова вызывается при декодировании начала каждой зафиксированной транзакции. Прерванные транзакции и их содержимое никогда не декодируются.
typedef void (*LogicalDecodeBeginCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn);
Параметр
txn
Параметр содержит метаинформацию о транзакции, такую как временная метка фиксации и её идентификатор XID.
Обязательная
commit_cb
Данная функция обратного вызова вызывается при каждом декодировании фиксации транзакции.
change_cb
Функции обратного вызова для всех измененных строк будут вызваны до этого момента, если такие строки имелись.
typedef void (*LogicalDecodeCommitCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr commit_lsn);
Обязательная
change_cb
функция обратного вызова вызывается для каждого отдельного изменения строки внутри транзакции, будь то
INSERT
,
UPDATE
,
или
DELETE
. Даже если исходная команда изменила несколько строк одновременно, функция обратного вызова будет вызвана отдельно для каждой строки.
change_cb
Функция обратного вызова может обращаться к системным таблицам или таблицам каталога пользователя для обеспечения процесса вывода сведений об изменениях строк. При декодировании подготовленной (но еще не зафиксированной) или незафиксированной транзакции данная функция обратного вызова может завершиться ошибкой вследствие параллельного отката этой транзакции. В таком случае логическое декодирование прерванной транзакции корректно останавливается.
typedef void (*LogicalDecodeChangeCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
Relation relation,
ReorderBufferChange *change);
Параметр
ctx
и
txn
параметры
имеют то же содержимое, что и для функций
begin_cb
и
commit_cb
, но дополнительно передаются дескриптор отношения
relation
, указывающий на отношение, к которому относится строка, и структура
change
, описывающая изменение строки.
Только изменения в пользовательских таблицах, которые не являются нежурналируемыми
(см.
UNLOGGED
) или временными
(см.
TEMPORARY или TEMP
), могут быть извлечены с использованием
логическое декодирование.
Необязательная
truncate_cb
функция обратного вызова вызывается для
TRUNCATE
команды.
typedef void (*LogicalDecodeTruncateCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
int nrelations,
Relation relations[],
ReorderBufferChange *change);
Данные параметры аналогичны параметрам функции
change_cb
callback. Однако, поскольку
TRUNCATE
действия над таблицами, связанными внешними ключами, должны выполняться совместно, данная функция обратного вызова получает массив отношений (relations) вместо одного объекта. Подробности приведены в описании оператора
TRUNCATE
оператор для получения подробных сведений.
Необязательная функция
filter_by_origin_cb
callback
вызывается для определения того, должны ли данные, воспроизведенные
из
origin_id
представляет интерес для
плагина вывода.
typedef bool (*LogicalDecodeFilterByOriginCB) (struct LogicalDecodingContext *ctx,
RepOriginId origin_id);
Параметр
ctx
параметр содержит те же данные,
что и для остальных функций обратного вызова. Доступна только информация об источнике. Чтобы указать, что изменения, исходящие от переданного узла, не являются релевантными, верните значение true, что приведет к их фильтрации; в противном случае верните false. Остальные функции обратного вызова не будут вызываться
для транзакций и изменений, которые были отфильтрованы.
Это полезно при реализации каскадных или многонаправленных схем репликации. Фильтрация по источнику позволяет предотвратить повторную репликацию одних и тех же изменений в таких конфигурациях. Хотя транзакции и изменения также несут информацию об источнике, фильтрация через данную функцию обратного вызова значительно более эффективна.
Необязательная
message_cb
функция обратного вызова вызывается при каждом декодировании сообщения логического декодирования.
typedef void (*LogicalDecodeMessageCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr message_lsn,
bool transactional,
const char *prefix,
Size message_size,
const char *message);
Параметр
txn
параметр содержит метаинформацию о
транзакции, такую как временная метка её фиксации и
её XID. Однако обратите внимание, что он может иметь значение NULL, если сообщение является
нетранзакционным и XID ещё не был назначен в транзакции,
которая записала сообщение. Параметр
LSN
содержит
расположение сообщения в WAL. Параметр
transactional
указывает,
было ли сообщение отправлено как транзакционное или нет. Подобно функции обратного вызова
для изменений, при декодировании подготовленной (но ещё не зафиксированной)
транзакции или декодировании незафиксированной транзакции, эта функция обратного вызова сообщений
может завершиться ошибкой из-за одновременного отката
этой же самой транзакции. В этом случае логическое декодирование этой прерванной транзакции корректно завершается.
prefix
— это произвольный префикс, завершающийся нулем, который может использоваться для идентификации сообщений, представляющих интерес для текущего плагина. И наконец, параметр
message
параметр содержит само сообщение
message_size
размера.
Необходимо позаботиться о том, чтобы префикс, используемый плагином вывода, был уникальным. Хорошим решением часто является использование названия расширения или самого плагина вывода.
Необязательная функция
filter_prepare_cb
callback
вызывается для определения того, следует ли учитывать данные, относящиеся к текущей
транзакции двухфазной фиксации, при декодировании
на данном этапе подготовки или позже, как обычную однофазную транзакцию, во время выполнения
COMMIT PREPARED
. Чтобы указать, что
декодирование следует пропустить, функция должна вернуть значение
true
;
false
в противном случае. Если функция обратного вызова не
определена,
false
предполагается значение по умолчанию (т. е. фильтрация отсутствует, и все
транзакции с двухфазной фиксацией также декодируются в две фазы).
typedef bool (*LogicalDecodeFilterPrepareCB) (struct LogicalDecodingContext *ctx,
TransactionId xid,
const char *gid);
Параметр
ctx
имеет то же содержимое, что и в
других функциях обратного вызова. Параметры
xid
и
gid
предоставляют два различных способа идентификации
транзакции. Последующие функции
COMMIT PREPARED
или
ROLLBACK PREPARED
передают оба идентификатора,
предоставляя плагину вывода возможность выбора используемого идентификатора.
Функция обратного вызова может вызываться несколько раз в рамках одной транзакции для декодирования
и должна возвращать идентичный статический ответ для заданной пары
xid
и
gid
при каждом
ее вызове.
Обязательная
begin_prepare_cb
функция обратного вызова вызывается
при декодировании начала подготовленной транзакции. Поле
gid
которое является частью параметра
txn
может использоваться в данной функции для
проверки того, получал ли плагин уже эту команду
PREPARE
в этом случае он может либо вернуть ошибку, либо пропустить остальные изменения транзакции.
typedef void (*LogicalDecodeBeginPrepareCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn);
Обязательная
prepare_cb
функция обратного вызова вызывается всякий раз, когда была декодирована транзакция, подготовленная для двухфазной фиксации.
change_cb
функции обратного вызова для всех измененных строк будут вызваны до этого момента, если измененные строки присутствовали. Параметр
gid
которое является частью параметра
txn
может быть использован в данной функции обратного вызова.
typedef void (*LogicalDecodePrepareCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr prepare_lsn);
Обязательная
commit_prepared_cb
функция обратного вызова вызывается
каждый раз, когда транзакция
COMMIT PREPARED
была декодирована.
Параметр
gid
которое является частью параметра
txn
может быть использован в данной функции обратного вызова.
typedef void (*LogicalDecodeCommitPreparedCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr commit_lsn);
Обязательная
rollback_prepared_cb
функция обратного вызова вызывается
каждый раз, когда транзакция
ROLLBACK PREPARED
была
декодирована. Параметр
gid
которое является частью параметра
txn
может быть использован в данной функции обратного вызова. Параметры
prepare_end_lsn
и
prepare_time
могут быть использованы для проверки того, получал ли плагин эту
PREPARE TRANSACTION
в этом случае
он может применить откат, в противном случае операция отката может быть пропущена. Параметр
gid
сам по себе недостаточен, так как подчиненный узел может иметь подготовленную транзакцию с таким же идентификатором.
typedef void (*LogicalDecodeRollbackPreparedCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr prepare_end_lsn,
TimestampTz prepare_time);
Обязательная
stream_start_cb
Функция обратного вызова вызывается при открытии блока изменений, передаваемых в потоке, из незавершенной транзакции.
typedef void (*LogicalDecodeStreamStartCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn);
Обязательная
stream_stop_cb
Функция обратного вызова вызывается при закрытии блока изменений, передаваемых в потоке, из незавершенной транзакции.
typedef void (*LogicalDecodeStreamStopCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn);
Обязательная
stream_abort_cb
функция обратного вызова вызывается для отмены транзакции, ранее переданной в потоке.
typedef void (*LogicalDecodeStreamAbortCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr abort_lsn);
Параметр
stream_prepare_cb
Функция обратного вызова вызывается для подготовки ранее переданной в потоке транзакции в рамках двухфазной фиксации. Данная функция обратного вызова требуется, когда плагин вывода поддерживает одновременно потоковую передачу больших незавершенных транзакций и двухфазные фиксации.
typedef void (*LogicalDecodeStreamPrepareCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr prepare_lsn);
Обязательная
stream_commit_cb
Данная функция вызывается для фиксации ранее переданной в потоке транзакции.
typedef void (*LogicalDecodeStreamCommitCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr commit_lsn);
Обязательная
stream_change_cb
Данная функция вызывается
при отправке изменения в блоке потоковых изменений (разграниченных
stream_start_cb
и
stream_stop_cb
вызовами). Фактические изменения не отображаются, так как транзакция может быть прервана позже, а изменения для прерванных транзакций не декодируются.
typedef void (*LogicalDecodeStreamChangeCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
Relation relation,
ReorderBufferChange *change);
Необязательная
stream_message_cb
Данная функция вызывается при
отправке универсального сообщения в блоке потоковых изменений (разграниченных
stream_start_cb
и
stream_stop_cb
вызовами).
Содержимое транзакционных сообщений не отображается, так как транзакция
может быть прервана позже, а изменения для прерванных
транзакций не декодируются.
typedef void (*LogicalDecodeStreamMessageCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr message_lsn,
bool transactional,
const char *prefix,
Size message_size,
const char *message);
Необязательная
stream_truncate_cb
функция обратного вызова вызывается
для команды
TRUNCATE
в блоке потоковых изменений
(ограниченном
stream_start_cb
и
stream_stop_cb
вызовами).
typedef void (*LogicalDecodeStreamTruncateCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
int nrelations,
Relation relations[],
ReorderBufferChange *change);
Данные параметры аналогичны параметрам функции
stream_change_cb
callback. Однако, поскольку
TRUNCATE
действия над таблицами, связанными внешними ключами, должны выполняться совместно, данная функция обратного вызова получает массив отношений (relations) вместо одного объекта. Подробности приведены в описании оператора
TRUNCATE
оператор для получения подробных сведений.
Для фактического формирования вывода плагины вывода могут записывать данные в
StringInfo
выходной буфер
в
ctx->out
при нахождении внутри
begin_cb
,
commit_cb
,
или
change_cb
функций обратного вызова. Перед записью в выходной
буфер
OutputPluginPrepareWrite(ctx, last_write)
должна быть вызвана, а после завершения записи в буфер —
OutputPluginWrite(ctx, last_write)
должна быть вызвана для выполнения записи. Параметр
last_write
указывает, была ли конкретная операция записи последней для функции обратного вызова.
В следующем примере показано, как вывести данные потребителю плагина вывода:
OutputPluginPrepareWrite(ctx, true); appendStringInfo(ctx->out, "BEGIN %u", txn->xid); OutputPluginWrite(ctx, true);