深度解析 PostgreSQL Protocol v3.0(三)— 流复制(上)
01 流复制介绍
PostgreSQL 支持 COPY 操作,COPY 操作通过流复制协议(Streaming Replication Protocol)实现。COPY 命令允许在服务器之间进行高速批量数据传输,有三种流复制模式:
COPY-IN 模式
数据从客户端传输到服务器端。
COPY-OUT 模式
数据从服务器端传输到客户端。
COPY-BOTH 模式
服务器端和客户端数据可以双向传输。
COPY-IN 和 COPY-OUT 操作分别将连接切换到一个不同于正常命令处理的子协议中,该子协议一直持续到操作完成;不同于 COPY-IN 和 COPY-OUT 模式,COPY-BOTH 模式是从狭义上定义的流复制协议,我们将上述统一称为流复制协议。
COPY-IN 模式
当服务器端收到并执行 COPY FROM STDIN SQL 语句时,将启动 COPY-IN 模式(从客户端向服务器传输数据)。服务器端向客户端发送 CopyInResponse 消息。然后,客户端应该发送 0 个或多个 CopyData 消息,形成一个输入数据流。
消息边界与行边界保持一致看似是一个合理的选择,但实际上它们没有任何关系,也不是必需的。客户端可以通过发送 CopyDone 消息(允许成功终止)或 CopyFail 消息(将导致 COPY SQL 语句执行失败并返回错误)来终止 COPY-IN 模式。然后,服务器端将恢复到 COPY 启动前的正常命令处理模式——简单查询协议或扩展查询协议流程。服务器端接下来将发送 CommandComplete(如果执行成功)或 ErrorResponse(如果执行失败)。
如果在执行 COPY-IN 模式期间服务器端检测到错误(包括收到 CopyFail 消息),将发出 ErrorResponse 消息。如果 COPY 命令是通过扩展查询消息发出的,则服务器端将立即丢弃客户端消息,直到收到 Sync 消息,然后服务器端将发出 ReadyForQuery 消息并返回正常处理。如果 COPY 命令是在简单查询的 Query 消息中发出的,则该消息的其余部分将被丢弃,服务器端发出 ReadyForQuery 消息。在前述任何一种情况下,客户端发出的任何后续 CopyData、CopyDone 或 CopyFail 消息都将被丢弃。
服务器端在 COPY-IN 模式中将忽略接收到的 Flush 和 Sync 消息。服务器端接收到任何其他非复制消息类型都会被算作一个错误,该错误将中止上述的 COPY-IN 状态。需要注意的是,Flush 和 Sync 作为例外情况是为了方便客户端库,客户端总是在 Execute 消息后发送 Flush 或 Sync,而不检查要执行的命令是否为 COPY FROM STDIN。
COPY-OUT 模式
当服务器端接收并执行 COPY TO STDOUT SQL 语句时,将启动 COPY-OUT 模式(从服务器向外传输数据)。服务器端向客户端端发送一条 CopyOutResponse 消息,然后是 0 条或多条 CopyData 消息(总是每行一条),后跟 CopyDone 消息。然后,服务器端恢复到 COPY 启动前的命令处理模式,并发送 CommandComplete。
客户端无法中止传输(除非关闭连接或发出 Cancel 请求),但它可以丢弃不需要的 CopyData 和 CopyDone 消息。如果服务器端在 COPY-OUT 模式期间检测到错误,将发出 ErrorResponse 消息并恢复到正常处理模式。客户端应将收到 ErrorResponse 视为终止 COPY-OUT 模式。
NoticeResponse 和 ParameterStatus 消息可以散布在 CopyData 消息之间;客户端必须处理这些情况,并应为其他异步消息类型做好准备。除此之外,除 CopyData 或 CopyDone 之外的任何消息类型都可能被视为终止 COPY-OUT 模式。
COPY-BOTH 模式
COPY-BOTH 是一种与 COPY 相关的模式,它允许在服务器之间或服务器与客户端之间进行高速批量数据传输。当处于 Walsender 模式中的服务器端执行 START_REPLICATION 语句时,将启动 COPY-BOTH 模式。服务器端向客户端发送 CopyBothResponse 消息。然后,服务器端和客户端都可以发送 CopyData 消息,直到任意一端发送 CopyDone 消息。
客户端发送 CopyDone 消息后,连接将从 COPY-BOTH 模式切换到 COPY-OUT 模式,并且客户端不可以再发送任何 CopyData 消息。类似地,当服务器发送 CopyDone 消息时,连接将切换到 COPY-IN 模式,并且服务器不可以再发送任何 CopyData 消息。当服务器端和客户端双方都发送了 CopyDone 消息后,COPY 模式将终止,服务器端将恢复到正常的命令处理模式。
如果服务器端在 COPY-BOTH 模式期间检测到错误,将发出 ErrorResponse 消息,丢弃客户端消息,直到收到 Sync 消息,然后发出 ReadyForQuery 消息并返回正常处理模式。客户端应将收到 ErrorResponse 视为终止双向复制;在这种情况下,不应发送 CopyDone 消息。
CopyInResponse、CopyOutResponse 和 CopyBothResponse 消息包含向客户端通知每行的列数以及每列使用的格式代码的字段。在目前的实现中,给定 COPY 操作中的所有列都将使用相同的格式,但消息格式的设计并不做这样的假设。
02 复制命令
当需要启动流复制时,客户端端会在 StartupMessage 消息中发送 replication 参数。replication 参数的布尔值 true(或 on,yes,1)告诉服务器端进入物理复制 Walsender 模式,其中可以发出如一小组复制命令,而不是 SQL 语句。
如果 replication 参数的值设置为 replication=database,会指示服务器端进入逻辑复制 Walsender 模式,连接到 dbname 参数中指定的数据库。在逻辑复制 Walsender 模式中,可以发出复制命令以及普通的 SQL 命令。在物理复制或逻辑复制 Walsender 模式中,只能使用简单的查询协议。
为了测试复制命令,可以使用带有包括 replication 选项的连接字符串的工具,通过 psql 或任何其他 libpq 驱动建立复制连接。例如,建立逻辑复制连接:
Shell
psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
但是,使用 pg_receivewal(用于物理复制)或 pg_recvlogic(用于逻辑复制)工具通常更有用。如果连接中
log_replication_commands 启用时,复制命令会记录在服务器日志中。
在复制模式下可以接受的命令包括以下 8 种:IDENTIFY_SYSTEM、SHOW name、TIMELINE_HISTORY、CREATE_REPLICATION_SLOT、START_REPLICATION、START_REPLICATION LOGICAL、DROP_REPLICATION_SLOT、BASE_BACKUP。
(1)IDENTIFY_SYSTEM
请求服务器标识自己。服务器使用单行的结果集进行回复,该结果集包含四个字段:
systemid (text):标识集群的唯一系统标识符。使用该字段可以检查用于初始化待命状态的基础备份是否来自同一集群。
timeline (int4):当前时间线 ID。也可以用于检查待命状态是否与主集群状态一致。
xlogpos (text):当前 WAL flush 位置。用于在 WAL 中获取可以启动流的已知位置。
dbname (text):连接的目标数据库。可以为 null。
(2)SHOW name
name:运行时参数的名称。支持的参数名称此处不再赘述,参考服务器配置。
请求服务器发送运行时参数的当前设置值。类似于 SQL 命令 SHOW。
(3)TIMELINE_HISTORY
完整命令为:
TIMELINE_HISTORY tli
请求服务器发送覆盖时间线 tli 的时间线历史文件。服务器使用单行的结果集进行回复,该结果集包含两个字段。字段被标记为 text,但它们有效地返回原始字节,无需编码转换:
filename (text):时间线历史文件的文件名,例如 00000002.history。
content (text):时间线历史文件的内容。
(4)CREATE_REPLICATION_SLOT
完整命令为:
CREATE_REPLICATION_SLOT slot_name [ TEMPORARY ] { PHYSICAL [ RESERVE_WAL ] | LOGICAL output_plugin [ EXPORT_SNAPSHOT | NOEXPORT_SNAPSHOT | USE_SNAPSHOT ] }
创建物理或逻辑复制插槽。关于复制插槽此处不再赘述,详细信息可以参考复制插槽。 slot_name:要创建的插槽的名称。必须是有效的复制插槽名称,它可以包含小写字母、数字和下划线。
output_plugin:用于逻辑解码的输出插件的名称。详情可以参考逻辑解码输出插件。
TEMPORARY:指定此复制插槽为临时插槽。临时插槽不会保存到磁盘,并且会在出现错误或会话结束时自动删除。
RESERVE_WAL:指定此物理复制插槽立即保留 WAL。否则,WAL 仅在从流复制客户端连接时保留。
EXPORT_SNAPSHOT, NOEXPORT_SNAPSHOT, USE_SNAPSHOT:决定如何处理在逻辑插槽初始化期间创建的快照。EXPORT_SNAPSHOT 是默认值,它将导出快照以便在其他会话中使用。此选项不能在事务内部使用。USE_SNAPSHOT 将为执行该命令的当前事务使用快照。此选项必须在事务中使用,并且 CREATE_REPLICATION_SLOT 必须是该事务中运行的第一个命令。最后,NOEXPORT_SNAPSHOT 将正常使用快照进行逻辑解码,但不会对其执行任何其他操作。
作为对 CREATE_REPLICATION_SLOT 命令的响应,服务器将发送一个包含以下字段的单行结果集:
slot_name (text):新创建的复制插槽的名称。
consistent_point (text):插槽变得一致的 WAL 位置。这是可以在此复制插槽上启动流的最早位置。
snapshot_name (text):命令导出的快照的标识符。在该连接上执行新命令或关闭复制连接之前,快照一直有效。如果创建的插槽是物理插槽,则为 null。
output_plugin (text):新创建的复制插槽使用的输出插件的名称。如果创建的插槽是物理插槽,则为 null。
(5)START_REPLICATION
完整命令为:
START_REPLICATION [ SLOT slot_name ] [ PHYSICAL ] XXX/XXX [ TIMELINE tli ]
指示服务器从 WAL 的位置 XXX/XX 开始流式传输 WAL。如果指定了 TIMELINE 选项,则流复制从时间线 tli 处开始;否则,将选择服务器的当前时间线。服务器可能会回复一个错误,例如,如果请求的 WAL 部分已经被回收。服务器处理成功后,将使用 CopyBothResponse 消息进行响应,然后开始将 WAL 流式传输到客户端。
如果插槽的名称是通过 slot_name 提供的,则它将随着复制的进行而更新,以便服务器知道备机仍然需要哪些 WAL 段,以及 hot_standby_feedback 是否在事务上依然有效。 如果客户端请求的时间线不是最新的,但是服务器历史的一部分,则服务器将流式传输该时间线上从请求的起始点开始直到服务器切换到另一个时间线为止的所有 WAL。如果客户端在旧时间线的末尾请求流式传输,则服务器将完全跳过 COPY 模式。
在非最新时间线上流式传输所有 WAL 后,服务器将退出 COPY 模式以结束流式传输。当客户端通过退出 COPY 模式来确认这一点时,服务器会发送一个包含一行两列的结果集,指示该服务器历史中的下一个时间线。第一列是下一个时间线的 ID(类型为 int8),第二列是发生切换的 WAL 位置(类型为 text)。
通常,切换位置是流式传输的 WAL 的末尾,但在某些情况下,服务器可以从旧的时间线发送一些 WAL,这些 WAL 是在时间线向前推进之前,服务器本身没有发送的 WAL。最后,服务器发送两条 CommandComplete 消息(一条结束 CopyData,另一条结束 START_REPLICATION 命令本身),并准备接收新命令。
WAL 数据以一系列 CopyData 消息的形式发送。CopyData 消息之间允许混合其他信息。特别是,如果服务器在开始流式传输后遇到故障,则可以发送 ErrorResponse 消息。从服务器到客户端的每个 CopyData 消息的有效负载都包含以下格式之一的消息:
→ XLogData (B)
Byte1('w'):将消息标识为 WAL 数据。
Int64:此消息中 WAL 数据的起点。
Int64:服务器上 WAL 的当前结束。
Int64:服务器在传输时的系统时钟,自 2000-01-01 午夜起以微秒为单位。
Byten:WAL 数据流的部分数据。单个 WAL 记录永远不会拆分为两条 XLogData 消息。当 WAL 记录越过 WAL 页面边界,因此已经使用连续记录进行拆分时,可以在页面边界进行拆分。也就是说,第一个主 WAL 记录及其后续记录可以在不同的 XLogData 消息中发送。
→ Primary keepalive message (B)
Byte1('k'):将消息标识为 sender keepalive。 Int64:服务器上 WAL 的当前结束。
Int64:服务器在传输时的系统时钟,自 2000-01-01 午夜起以微秒为单位。
Byte1:1,表示客户端应尽快回复此消息,以避免超时断开连接;否则为 0。
客户端接收进程可以随时使用以下消息格式之一(在 CopyData 消息的有效载荷中)将回复发送回 sender:
→ Standby status update (F)
Byte1('r'):将消息标识为接收方状态更新。 Int64:在备机接收并写入磁盘的最后一个 WAL 字节 + 1 的位置。
Int64:在备机刷新到磁盘的最后一个 WAL 字节 + 1 的位置。
Int64:在备机应用的最后一个 WAL 字节 + 1 的位置。
Int64:传输时客户端的系统时钟,自 2000-01-01 午夜起以微秒为单位。
Byte1:1,客户端请求服务器立即回复此消息,可以用来 ping 服务器以测试连接是否仍然正常。
→ Hot Standby feedback message (F)
Byte1('h'):将消息标识为热备反馈消息。
Int64:传输时客户端的系统时钟,自 2000-01-01 午夜起以微秒为单位。
Int32:备机的当前全局 xmin,不包括任何复制插槽中的 catalog_xmin。如果 xmin 和下面的 catalog_xmin 都为 0,则将被视为不再在此连接上发送热备反馈的通知。稍后的非 0 消息可以重新启动反馈机制。
Int32:备机的全局 xmin xid 的 epoch。
Int32:备机复制插槽中最低的 catalog_xmin。如果备机上不存在 catalog_xmin,或者热备反馈被禁用,则设置为 0。
Int32:备机的 catalog_xmin xid 的 epoch。
(6)START_REPLICATION LOGICAL
完整命令为:
START_REPLICATION SLOT slot_name LOGICAL XXX/XXX [ ( option_name [ option_value ] [, ...] ) ]
START_REPLICATION SLOT slot_name LOGICAL XXX/XXX [ ( option_name [ option_value ] [, ...] ) ] 指示服务器从 WAL 位置 XXX/XXX 开始流式传输 WAL 以进行逻辑复制。服务器可能会回复一个错误,例如,如果请求的 WAL 部分已经被回收。服务器处理成功后,将使用 CopyBothResponse 消息进行响应,然后开始将 WAL 流式传输到客户端。
CopyBothResponse 消息中的消息与 START_REPLICATION ... PHYSICAL 文档中的格式相同,包括两条 CommandComplete 消息。与所选插槽关联的输出插件用于处理流式传输的输出。
SLOT slot_name:要变更的流式传输的插槽名称。此参数是必需的,并且必须与在 LOGICAL 模式下使用 CREATE_REPLICATION_SLOT 创建的现有逻辑复制插槽相对应。
XXX/XXX:开始流式传输的 WAL 位置。 option_name:传递到插槽的逻辑解码插件的选项的名称。
option_value:与指定选项关联的字符串常量形式的可选值。
(7)DROP_REPLICATION_SLOT
完整命令为:
DROP_REPLICATION_SLOT slot_name [ WAIT ]
删除复制插槽,释放所有保留的服务器端资源。如果插槽是在 Walsender 连接的数据库之外的数据库中创建的逻辑插槽,则此命令将失败。 slot_name:要删除的插槽的名称。 WAIT:如果插槽处于活动状态,此选项会导致命令等待,直到它变为非活动状态,而不是引发错误的默认行为。
(8)BASE_BACKUP
完整命令为:
BASE_BACKUP [ LABEL 'label' ] [ PROGRESS ] [ FAST ] [ WAL ] [ NOWAIT ] [ MAX_RATE rate ] [ TABLESPACE_MAP ] [ NOVERIFY_CHECKSUMS ] [ MANIFEST manifest_option ] [ MANIFEST_CHECKSUMS checksum_algorithm ]
指示服务器开始流式传输基础备份。系统将在备份开始前自动进入备份模式,并在备份完成后退出。BASE_BACKUP 命令接受以下选项:
LABEL 'label':设置备份的标签。如果未指定,则将使用 base backup 的备份标签。标签的引用规则与打开 standard_conforming_strings 的标准 SQL 字符串相同。
PROGRESS:请求生成进度报告所需的信息。这将在每个表空间的头中发送回一个近似大小,该大小可用于计算流复制的执行进度。这是通过在传输开始之前遍历一次所有文件大小来计算的,因此可能会对性能产生负面影响。特别是,可能需要更长的时间才能开始流式传输第一个数据。由于数据库文件在备份过程中可能会发生变化,因此大小只是近似值,在近似值和发送实际文件大小之间可能会增长和减少。
FAST:请求快速检查点。
WAL:在备份中包括必要的 WAL 段。这将包括基准目录 tar 文件的 pg_wal 目录中启动和停止备份之间的所有文件。
NOWAIT:默认情况下,备份将等待最后一个所需的 WAL 段存档,或者如果未启用日志存档,则会发出警告。指定 NOWAIT 将禁用等待和警告,让客户端负责确保所需的日志可用。
MAX_RATE rate:限制每单位时间从服务器传输到客户端的最大数据量。预期的单位是 KB/s(千字节每秒)。如果指定了此选项,则该值必须等于零,或者必须在 32 kB 到 1 GB(包括 32 kB 和 1 GB)的范围内。如果指定选项为 0 或未指定选项,则不会对传输施加任何限制。
TABLESPACE_MAP:在名为 tablespace_map 的文件中包含有关目录 pg_tblspc 中存在的符号链接的信息。表空间映射文件包括目录 pg_tblspc/ 中存在的每个符号链接名称以及该符号链接的完整路径。
NOVERIFY_CHECKSUMS:默认情况下,如果启用了校验和,则会在基础备份期间验证校验和。指定 NOVERIFY_CHECKSUMS 将禁用此验证。
MANIFEST manifest_option:如果指定此选项的值为 yes 或 force-encode,则会创建备份清单并将其与备份一起发送。清单是备份中存在的每个文件的列表,但可能包括的任何 WAL 文件除外。它还存储每个文件的大小、上次修改时间以及可选的校验和。force-encode 的值强制所有文件名进行十六进制编码;否则,仅对名称为非 UTF8 八位位组序列的文件执行这种类型的编码。force-encode 主要用于测试目的,以确保读取备份清单的客户端能够处理这种情况。为了与以前的版本兼容,默认值为 MANIFEST 'no'。
MANIFEST_CHECKSUMS checksum_algorithm:指定应用于备份清单中包含的每个文件的校验和算法。目前,可用的算法有 NONE、CRC32C、SHA224、SHA256、SHA384 和 SHA512。默认值为 CRC32C。
启动备份时,服务器将首先发送两个普通结果集,然后发送一个或多个 CopyOutResponse 结果。
第一个普通结果集为一行两列,包含备份的起始位置。第一列包含以 XLogRecPtr 格式给定的开始位置,第二列包含相应的时间线 ID。
第二个普通结果集为每个表空间有一行。此行中的字段为:
spcoid (oid):表空间的 OID,如果是基准目录,则为 null。
spclocation (text):表空间目录的完整路径,如果是基准目录,则为 null。
size (int8):如果请求了进度报告,则值为表空间的大致大小,以 KB(1024 字节)为单位;否则为 null。
在第二个常规结果集之后,将发送一个或多个 CopyOutResponse 结果,一个用于主数据目录,其他的用于除 pg_default 和 pg_global 之外的每个附加表空间。CopyOutResponse 结果中的数据,除了省略了标准中规定的两个包含 0 值的块之外,是表空间内容的 tar 格式转储(遵循 POSIX 1003.1-2008 标准中指定的“ustar 交换格式”)。
tar 数据完成后,如果请求了备份清单,则会发送另一个 CopyOutResponse 结果,其中包含当前基础备份的清单数据。在任何情况下,都会发送一个最终的普通结果集,其中包含备份的 WAL 结束位置,格式与开始位置相同。
数据目录和每个表空间的 tar 存档将包含目录中的所有文件,无论它们是 PostgreSQL 文件还是添加到同一目录中的其他文件。只排除以下文件:
postmaster.pid
postmaster.opts
pg_internal.init:在多个目录中存在。
PostgreSQL 服务器运行过程中创建的各种临时文件和目录,例如以 pgsql_tmp 开头的任何文件或目录以及临时关系表。
未标记的关系表。除了在恢复时重新创建(空的)未标记关系需要的初始化复制文件。
pg_wal,包括子目录。如果备份是在包含 WAL 文件的情况下运行的,则会包含 pg_wal 的合成版本,但它只包含备份工作所需的文件,而不包含其余内容。
pg_dynshmem、pg_notify、pg_replslot、pg_serial、pg_snapshots、pg_stat_tmp 和 pg_subtrans 被复制为空目录(即使它们是符号链接)。
跳过常规文件和目录以外的文件,如符号链接(上面列出的目录除外)和特殊设备文件。pg_tblspc 中的符号链接将得到保留维护。
如果服务器上的底层文件系统支持,则会设置所有者、组和文件模式。
03 逻辑流复制协议
逻辑复制协议,是由 START_REPLICATION SLOT slot_name LOGICAL 复制命令启动的消息流。逻辑流复制协议建立在物理流复制协议的基础之上。
(1)逻辑流复制参数
逻辑复制 START_REPLICATION 命令接受以下参数:
proto_version:协议版本。目前支持版本 1 和版本 2。版本 2 仅支持服务器版本 14 及更高版本,并且它允许对正在进行的大型事务进行流式传输。
publication_names:要订阅(接收更改)的发布名称的逗号分隔列表。各个发布名称被视为标准对象名称,并且可以根据需要引用相同的名称。
(2)逻辑复制协议消息
所有顶层协议消息都以消息类型字节作为开头。虽然在代码中表示为字符,但这是一个没有关联编码的带符号字节。由于流复制协议提供消息长度,因此顶层协议消息不需要在其标头中嵌入长度。每个逻辑复制消息要么由复制槽 SQL 接口返回,要么由 Walsender 发送。在 Walsender 的情况下,它们被封装在复制协议 WAL 消息中,并且通常遵循与物理复制相同的消息流。
1.Begin
Byte1('B'):将消息标识为开始消息。
Int64:事务的最终 LSN。
Int64:事务的提交时间戳。该值以 PostgreSQL epoch(2000-01-01)以来的微秒为单位。
Int32:事务的 Xid。
2.Message
Byte1('M'):将消息标识为逻辑解码消息。
Int32:事务的 Xid(仅用于流式事务)。此字段自协议版本 2 起可用。
Int8:flags。0,表示没有标志;1 表示逻辑解码消息是事务性的。
Int64:逻辑解码消息的 LSN。
String:逻辑解码消息的前缀。
Int32:内容的长度。
Byten:逻辑解码消息的内容。
3.Commit
Byte1('C'):将消息标识为提交消息。
Int8:flags。当前未使用(必须为 0)。
Int64:提交的 LSN。
Int64:事务的结束 LSN。
Int64:事务的提交时间戳。该值以 PostgreSQL epoch(2000-01-01)以来的微秒为单位。
4.Origin
注意:在一个事务中可以有多个 Origin 消息。
Byte1('O'):将消息标识为 Origin 消息。
Int64:源服务器上提交的 LSN。
String:Origin 名称。
5.Relation
Byte1('R'):将消息标识为 Relation 消息。
Int32:事务的 Xid(仅用于流式事务)。此字段自协议版本 2 起可用。
Int32:Relation 的 ID。
String:命名空间(pg_catalog 命名空间为空字符串)。
String:Relation 名称。
Int8:Relation 的副本标识设置(与 pg_class 中的 relreplident 相同)。
Int16:列数量。
接下来,每个列(生成的列除外)都会显示以下消息部分:
Int8:列的标志。当前可以为 0 表示没有标志,也可以为 1 表示将列标记为 key 的一部分。
String:列名称。
Int32:列的数据类型的 ID。
Int32:列的类型修饰符(atttypmod)。
6.Type
Byte1('Y'):将消息标识为类型消息。
Int32:事务的 Xid(仅用于流式事务)。此字段自协议版本 2 起可用。
Int32:数据类型的 ID。
String:命名空间(pg_catalog 命名空间为空字符串)。
String:数据类型的名称。
7.Insert
Byte1('I'):将消息标识为插入消息。
Int32:事务的 Xid(仅用于流式事务)。此字段自协议版本 2 起可用。
Int32:与关系消息中的 ID 对应的关系的 ID。
Byte1('N'):将以下 TupleData 消息标识为新元组。
TupleData:表示新元组内容的 TupleData 消息部分。
8.Update
Byte1('U'):将消息标识为更新消息。
Int32:事务的 Xid(仅用于流式事务)。此字段自协议版本 2 起可用。
Int32:与关系消息中的 ID 对应的关系的 ID。
Byte1('K'):将以下 TupleData 子消息标识为键。此字段是可选的,仅当更新操作更改了 REPLICA IDENTITY 索引中任何列中的数据时才出现。
Byte1('O'):将以下 TupleData 子消息标识为旧元组。此字段是可选的,仅当发生更新的表的 REPLICA IDENTITY 设置为 FULL 时才存在。
TupleData:表示旧元组或主键内容的 TupleData 消息部分。仅当存在前一个 O 或 K 部分时才存在。
Byte1('N'):将以下 TupleData 消息标识为新元组。
TupleData:表示新元组内容的 TupleData 消息部分。
更新消息可能包含 K 消息部分或 O 消息部分,也可能两者都不包含,但决不能同时包含两者。
9.Delete
Byte1('D'):将消息标识为删除消息。
Int32:事务的 Xid(仅用于流式事务)。此字段自协议版本 2 起可用。
Int32:与关系消息中的 ID 对应的关系的 ID。
Byte1('K'):将以下 TupleData 子消息标识为键。如果发生删除的表使用了 REPLICA IDENTITY 的索引,则会出现此字段。
Byte1('O'):将以下 TupleData 消息标识为旧元组。如果发生删除的表的 REPLICA IDENTITY 设置为 FULL,则会出现此字段。
TupleData:TupleData 消息部分表示旧元组或主键的内容,具体取决于前一个字段。
Delete 消息可能包含 K 消息部分或 O 消息部分,但决不能同时包含这两个部分。
10.Truncate
Byte1('T'):将消息标识为 Truncate 消息。
Int32:事务的 Xid(仅用于流式事务)。此字段自协议版本 2 起可用。
Int32:关系的数量。
Int8:TRUNCATE 的选项位:1 用于 CASCADE,2 用于 RESTART IDENTITY。
Int32:与关系消息中的 ID 对应的关系的 ID。对于每个关系,都会重复此字段。 -自协议版本 2 以来,以下消息(流启动、流停止、流提交和流中止)可用。
11.Stream Start
Byte1('A'):将消息标识为流中止消息。
Int32:事务的 Xid。
Int32:子事务的 Xid(对于顶级事务,将和事务的 Xid 相同)。
12. Stream Stop
Byte1('E'):将消息标识为流停止消息。
Stream Commit
Byte1('c'):将消息标识为流提交消息。
Int32:事务的 Xid。
Int8:标识。当前未使用(必须为 0)。
Int64:提交的 LSN。
Int64:事务的结束 LSN。
Int64:事务的提交时间戳。该值以 PostgreSQL epoch(2000-01-01)以来的微秒为单位。
13.Stream Abort
Byte1('A'):将消息标识为流中止消息。
Int32:事务的 Xid。
Int8:值 1 表示这是该 XID 的第一个流段,0 表示任何其他流段。
14. 以下消息部分由上述消息共享:
TupleData,Int16:列数。接下来,每列(生成的列除外)都会显示以下子消息之一:
Byte1('n'):将数据标识为 NULL 值。
Byte1('u'):标识未更改的 TOASTed 值(不发送实际值)。
Byte1('t'):将数据标识为文本格式的值。
Byte1('b'):将数据标识为二进制格式的值。
Int32:列值的长度。
Byten:列的值,可以是二进制格式,也可以是文本格式。(如前面格式字节中所指定的)。n 是上述列值长度。
评论