# 49.6.逻辑解码输出插件
示例输出插件可以在contrib/test_解码
PostgreSQL源代码树的子目录。
# 49.6.1.初始化函数
通过以输出插件的名称作为库基名称动态加载共享库来加载输出插件。普通库搜索路径用于定位库。为了提供所需的输出插件回调,并表明库实际上是一个输出插件,它需要提供一个名为_PG_输出_插件_初始化
。此函数被传递给一个结构,该结构需要为单个操作填充回调函数指针。
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);
这个开始
,改变
和承诺
需要回调,而启动
,按来源过滤
,截断
和关机
是可选的。如果截断
不是设定的而是一个截断
如果要解码,该操作将被忽略。
一个输出插件还可以定义一些函数来支持大的、正在进行的事务流。这个流\u开始\u cb
, 流_停止_cb
, 流_中止_cb
, 流_提交_cb
, 流_变化_cb
和流_准备_cb
是必需的,而流消息
和流_截断_cb
是可选的。
输出插件还可以定义支持两阶段提交的函数,这使得操作可以在服务器上解码准备交易
这个开始准备
, 准备
, 流_准备_cb
, 提交_准备_cb
和回滚\u准备\u cb
需要回调,而过滤器\u准备\u cb
是可选的。
# 49.6.2.能力
为了解码、格式化和输出更改,输出插件可以使用后端的大部分常规基础设施,包括调用输出函数。只要只访问由创建的关系,就允许对关系进行只读访问initdb
在pg_目录
架构,或已使用标记为用户提供的目录表
ALTER TABLE user_catalog_table SET (user_catalog_table = true);
CREATE TABLE another_catalog_table(data text) WITH (user_catalog_table = true);
请注意,对输出插件中的用户目录表或常规系统目录表的访问必须通过系统的_*
只扫描API。通过堆_*
扫描API将出错。此外,禁止任何导致事务ID分配的操作。其中包括写入表、执行DDL更改和调用pg_当前_xact_id()
.
# 49.6.3.输出模式
输出插件回调可以以几乎任意的格式将数据传递给消费者。对于某些用例,例如通过SQL查看更改,以可以包含任意数据的数据类型返回数据(例如。,二进制数据
)这很麻烦。如果输出插件只输出服务器编码中的文本数据,它可以通过设置输出插件操作。输出类型
到输出插件文本输出
而不是输出插件二进制输出
在启动回调.在这种情况下,所有数据必须采用服务器的编码,以便文本
数据可以包含它。这是在启用断言的版本中签入的。
# 49.6.4.输出插件回调
输出插件通过其需要提供的各种回调获得正在发生的更改的通知。
并发事务按照提交顺序进行解码,并且只有属于特定事务的更改才会在开始
和犯罪
回电。显式或隐式回滚的事务永远不会被解码。成功的保存点将按照在该事务中执行的顺序折叠到包含它们的事务中。为两阶段提交准备的事务,使用准备交易
如果提供了解码所需的输出插件回调,也将被解码。正在解码的当前准备好的事务可能会通过准备回滚
命令在这种情况下,该事务的逻辑解码也将中止。一旦检测到中止并且准备
调用回调。因此,即使在并发中止的情况下,也会向输出插件提供足够的信息,以便其正确处理准备回滚
一旦被解码。
# 笔记
只有已经安全地刷新到磁盘的事务才会被解码。这可能会导致犯罪
没有立即被解码成直接跟随pg_逻辑_插槽_获取_更改()
什么时候同步提交
即将关
.
# 49.6.4.1.启动回调
可选的启动
无论何时创建复制槽或要求对更改进行流式传输,都会调用回调,这与准备发布的更改数量无关。
typedef void (*LogicalDecodeStartupCB) (struct LogicalDecodingContext *ctx,
OutputPluginOptions *options,
bool is_init);
这个是吗
参数在创建复制插槽时为true,否则为false。*选项
*指向输出插件可以设置的选项结构:
typedef struct OutputPluginOptions
{
OutputPluginOutputType output_type;
bool receive_rewrites;
} OutputPluginOptions;
输出类型
必须设置为输出插件文本输出
或输出插件二进制输出
.另见第49.6.3节如果接受改写
如果为true,则在某些DDL操作期间,堆重写所做的更改也将调用输出插件。这些是处理DDL复制的插件感兴趣的,但它们需要特殊处理。
启动回调应该验证中存在的选项ctx->输出插件选项
.如果输出插件需要有一个状态,它可以使用ctx->output_plugin_private
储存它。
# 49.6.4.2.关机回调
可选的关机
只要不再使用以前活动的复制插槽,就会调用callback,它可以用于解除分配输出插件专用的资源。插槽不一定会被删除,流媒体只是被停止。
typedef void (*LogicalDecodeShutdownCB) (struct LogicalDecodingContext *ctx);
# 49.6.4.3.事务开始回调
必要的开始
只要已提交事务的开始被解码,就会调用回调。中止的事务及其内容永远不会被解码。
typedef void (*LogicalDecodeBeginCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn);
这个*txn
*参数包含有关事务的元信息,如提交事务的时间戳及其XID。
# 49.6.4.4.事务结束回调
必要的承诺
每当事务提交被解码时,就会调用回调。这个改变
如果有任何修改过的行,在此之前将调用所有修改过的行的回调。
typedef void (*LogicalDecodeCommitCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr commit_lsn);
# 49.6.4.5.更改回拨
必要的改变
事务中的每一行修改都会调用回调,可能是插入
, 使现代化
或删去
。即使原始命令一次修改了几行,也会为每一行单独调用回调。这个改变
回调可以访问系统或用户目录表,以帮助输出行修改详细信息。在解码准备好的(但尚未提交的)事务或解码未提交的事务的情况下,此更改回调也可能因同时回滚同一事务而出错。在这种情况下,这个被中止事务的逻辑解码会正常停止。
typedef void (*LogicalDecodeChangeCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
Relation relation,
ReorderBufferChange *change);
这个*ctx
和txn
参数的内容与开始
和承诺
回调,但另外还有关系描述符关系
指向行所属的关系和结构改变
*描述行的修改被传入。
# 笔记
仅在用户定义的表中未取消标记的更改(请参阅解锁
)而不是暂时的(参见短暂的
或临时雇员
)可以使用逻辑解码提取。
# 49.6.4.6.截断回调
这个截断
调用回调以获取截断
命令
typedef void (*LogicalDecodeTruncateCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
int nrelations,
Relation relations[],
ReorderBufferChange *change);
这些参数类似于改变
回拨。然而,因为截断
通过外键连接的表上的操作需要一起执行,这个回调接收一个关系数组,而不是一个关系数组。请参见对截断详细信息请参见声明。
# 49.6.4.7.原点过滤器回调
可选的按来源过滤
调用callback以确定是否从*起源号
*是输出插件感兴趣的。
typedef bool (*LogicalDecodeFilterByOriginCB) (struct LogicalDecodingContext *ctx,
RepOriginId origin_id);
这个*ctx
*参数的内容与其他回调的内容相同。没有信息,但来源是可用的。要表示传入节点上的更改不相关,请返回true,从而将它们过滤掉;否则就错了。对于已过滤掉的事务和更改,不会调用其他回调。
这在实施级联或多向复制解决方案时非常有用。按原点进行过滤可以防止在此类设置中来回复制相同的更改。虽然事务和更改也包含有关源代码的信息,但通过此回调进行过滤的效率明显更高。
# 49.6.4.8.通用消息回调
可选的信息_cb
每当逻辑解码消息被解码时,就会调用callback。
typedef void (*LogicalDecodeMessageCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr message_lsn,
bool transactional,
const char *prefix,
Size message_size,
const char *message);
这个*txn
参数包含有关事务的元信息,如提交事务的时间戳及其XID。但是,请注意,当消息是非事务性的,并且记录该消息的事务中尚未分配XID时,它可以为NULL。这个lsn
有消息的位置。这个交易的
说明消息是否作为事务性消息发送。与更改回调类似,在解码已准备(但尚未提交)的事务或解码未提交的事务的情况下,由于同时回滚同一事务,此消息回调也可能出错。在这种情况下,这个被中止事务的逻辑解码会正常停止。这个前缀
是任意以null结尾的前缀,可用于识别当前插件的有趣消息。最后是消息
参数保存消息大小
*大小
应该特别注意确保输出插件认为有趣的前缀是唯一的。使用扩展名或输出插件本身通常是一个不错的选择。
# 49.6.4.9.准备过滤器回调
可选的过滤器\u准备\u cb
调用callback以确定当前两阶段提交事务中的数据是否应在这个准备阶段或以后作为常规的一阶段事务在准备阶段进行解码做好准备
时间要指示应该跳过解码,请返回符合事实的
; 错误的
否则如果没有定义回调,错误的
假设为(即不进行过滤,所有使用两阶段提交的事务也分两阶段解码)。
typedef bool (*LogicalDecodeFilterPrepareCB) (struct LogicalDecodingContext *ctx,
TransactionId xid,
const char *gid);
这个*ctx
参数的内容与其他回调的内容相同。参数希德
和吉德
*提供两种不同的方式来识别交易。后者做好准备
或准备回滚
携带两个标识符,为输出插件提供使用选项。
每个事务可以多次调用回调进行解码,并且必须为给定的一对事务提供相同的静态答案*希德
和吉德
*每次它被叫来。
# 49.6.4.10.事务开始准备回调
必要的开始准备
每当准备好的事务的开始被解码时,就会调用callback。这个*吉德
字段,它是txn
*参数,可在此回调中使用,以检查插件是否已收到此消息准备
在这种情况下,它可以出错或跳过事务的其余更改。
typedef void (*LogicalDecodeBeginPrepareCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn);
# 49.6.4.11.事务准备回调
必要的准备
每当准备进行两阶段提交的事务被解码时,就会调用callback。这个改变
如果有任何修改的行,在此之前将调用所有修改行的回调。这个*吉德
字段,它是txn
*参数,可在此回调中使用。
typedef void (*LogicalDecodePrepareCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr prepare_lsn);
# 49.6.4.12.事务提交准备回调
必要的提交_准备_cb
每当事务发生时都会调用回调做好准备
已经被破译了。这个*吉德
字段,它是txn
*参数,可在此回调中使用。
typedef void (*LogicalDecodeCommitPreparedCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr commit_lsn);
# 49.6.4.13.事务回滚准备回调
必要的回滚\u准备\u cb
每当事务发生时都会调用回调准备回滚
已经被破译了。这个*吉德
字段,它是txn
参数,可在此回调中使用。参数准备结束
和准备时间
可用于检查插件是否已收到此消息准备交易
在这种情况下,它可以应用回滚,否则,它可以跳过回滚操作。这个吉德
*由于下游节点可以有一个具有相同标识符的已准备好的事务,因此单独处理是不够的。
typedef void (*LogicalDecodeRollbackPreparedCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr prepare_end_lsn,
TimestampTz prepare_time);
# 49.6.4.14.流启动回调
这个流\u开始\u cb
当打开正在进行的事务中的流式更改块时,将调用callback。
typedef void (*LogicalDecodeStreamStartCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn);
# 49.6.4.15.流停止回调
这个流_停止_cb
当关闭正在进行的事务中的流式更改块时,将调用callback。
typedef void (*LogicalDecodeStreamStopCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn);
# 49.6.4.16.流中止回调
这个流_中止_cb
调用callback以中止以前的流式事务。
typedef void (*LogicalDecodeStreamAbortCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr abort_lsn);
# 49.6.4.17.流准备回调
这个流_准备_cb
调用callback以作为两阶段提交的一部分准备之前的流式事务。
typedef void (*LogicalDecodeStreamPrepareCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr prepare_lsn);
# 49.6.4.18.流提交回调
这个流_提交_cb
调用callback以提交以前的流式事务。
typedef void (*LogicalDecodeStreamCommitCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr commit_lsn);
# 49.6.4.19.流更改回调
这个流_变化_cb
在流式更改块中发送更改时调用callback(以流\u开始\u cb
和流_停止_cb
电话)。实际的更改不会显示,因为事务可以在稍后的时间点中止,我们不会对中止的事务的更改进行解码。
typedef void (*LogicalDecodeStreamChangeCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
Relation relation,
ReorderBufferChange *change);
# 49.6.4.20.流消息回调
这个流消息
在以流式更改块(以流\u开始\u cb
和流_停止_cb
电话)。事务性消息的消息内容不会显示,因为事务可以在稍后的时间点中止,我们不会对中止的事务的更改进行解码。
typedef void (*LogicalDecodeStreamMessageCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
XLogRecPtr message_lsn,
bool transactional,
const char *prefix,
Size message_size,
const char *message);
# 49.6.4.21.流截断回调
这个流_截断_cb
调用回调以获取截断
流式更改块中的命令(以流\u开始\u cb
和流_停止_cb
电话)。
typedef void (*LogicalDecodeStreamTruncateCB) (struct LogicalDecodingContext *ctx,
ReorderBufferTXN *txn,
int nrelations,
Relation relations[],
ReorderBufferChange *change);
这些参数类似于流_变化_cb
回拨。然而,因为截断
通过外键连接的表上的操作需要一起执行,这个回调接收一个关系数组,而不是一个关系数组。请参见对截断详细信息请参见声明。
# 49.6.5.产生产出的功能
为了实际产生输出,输出插件可以将数据写入StringInfo
输出缓冲区在ctx->out
当进入开始
, 承诺
或改变
回电。在写入输出缓冲区之前,OutputPluginPrePreWrite(ctx,最后一次写入)
必须调用,在完成对缓冲区的写入后,OutputPluginWrite(ctx,最后一次写入)
必须调用才能执行写入。这个*最后一封信
*指示特定写入是否是回调的最后一次写入。
以下示例显示了如何向输出插件的使用者输出数据:
OutputPluginPrepareWrite(ctx, true);
appendStringInfo(ctx->out, "BEGIN %u", txn->xid);
OutputPluginWrite(ctx, true);