searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Tbase 分布式事务原理与源码

2023-08-28 03:39:24
92
0
  1. 全局 MVCC

PGXC的事务管理需要满足ACID,并确保集群中多节点读取事务的原子性。此功能通过MVCC实现。Postgres-XC 基本上使用 src/backend/utils/time/tqual.c 中实现的 PostgreSQL MVCC 机制:通过 xmin、xmax、CLOG 和事务快照检查可见性(有时包括 cmin 和 cmax)。Postgres-XC 只是扩展了 PostgreSQL 分配事务 ID 并将快照提供给全局。提供全局事务信息的外部组件称为全局事务管理器 (GTM),集群范围的 MVCC 依赖GTM实现。GTM与 CN 和DN 的分开实现。GTM的源代码在src/gtm/main 中。
 
当用户向 CN 发出 DML 语句时,CN 从GTM获取全局事务ID(GXID)和全局事务快照并将其发送到 DN。DN 使用 GXID 和来自 CN 的快照来操作其数据库。通过这种方式,DN 共享相同的事务上下文,并且事务在多个 CN 和 DN 中运行时可以保持原子性和统一的可见性。在事务结束时,如果多个节点参与更新,CN 会使用 2PC 协议隐式提交事务。通过跟踪全局事务状态,CN 向 GTM 报告全局事务状态。
 
可见性检查有时使用 CN 生成的本地事务命令 ID。在发送每个命令之前,它也会发送到 DN 。如果命令 ID 在某些涉及的 DN中本地提前接收到,它们会将更改通知给 CN。
 
PGXC 支持 PostgreSQL 中实现的所有事务隔离级别。如果事务隔离级别是REPEATABLE READ,则在整个事务中将获取并使用一个快照。如果隔离模式是 READ COMMITTED,CN 会获取每个语句的最新快照。如果 Planner 将一条语句分为多个语句,则此快照将用于多个语句。
 
需要进行一些小的更改才能使此全局 MVCC 与现有 PostgreSQL 代码一起运行。例如,CLOG扩展算法需要一些修改。在全局事务中,有些节点可能不参与,并且在这些节点中缺少该事务的GXID。 CLOG 需要一个扩展来处理这个缺失的 GXID,以使 CLOG 扩展正常工作,相关代码实现在src/backend/access/transam/clog.c:ExpandCLOG()。
 
  1. GTM

CN 在以下情况中与GTM进行通信
  1. CN 请求新的事务 ID
  2. CN 需要新的事务快照
  3. CN 提交或 abort 事务
DN只有在执行 vacuum 的时候与 GTM 通信。
下表列出了 GTM 和其他节点(CN, DN)之间用于全局事务管理的消息。此表显示了在 GTM 和 CN/DN 后端中实际实现的消息,不包括仅在 GTM 中实现但未真正使用的消息。
表1:事务控制消息
消息名
描述
TXN_BEGIN_GETGXID
开始一个新事务并获取 GXID
TXN_START_PREPARED
开始准备将要提交的事务
TXN_COMMIT
提交一个 running 或 prepared 的事务
TXN_COMMIT_PREPARED
提交一个 prepared 的事务
TXN_PREPARE
结束 preparing 一个事务
TXN_ROLLBACK
回滚一个事务
TXN_GET_GID_DATA
根据 GID 获取相关信息以及 GXID
SNAPSHOT_GET
获取全局快照
TXN_BEGIN_GETGXID_AUTOVACUUM
开始新事务并获取 GXID 用于自动vacuum
GTM客户端使用的实际协议在src/gtm/client/gtm_client.c中实现,这个原生实现无法从 CN/DN 后端调用。Utility函数作为这些原始实现的快捷方式在 src/backend/access/transam/gtm.c 中实现,如表2所示,GTM的工具函数分为四种:
  1. 它们处理与 GTM 的连接。这些函数被 gtm.c 内部的其他utility函数调用。InitGTM() 建立与 GTM 的连接并将连接信息存储到进程本地内存。该函数在内部调用 InitGTM(),并使用已保存的连接。 CloseGTM() 重置已保存的连接和信息。
  2. 向 GTM 查询新的全局事务 ID。这些函数被 varsup.c 中的函数调用,这些函数负责 OID 和 XID 变量支持。 varsup.c 中的函数使用上述的函数,而不是原始的本地 XID feed机制。
  3. 它们用于控制事务,被 xact.c 和 execRemote.c 中的函数调用。 xact.c 中的函数被修改为使用这些工具函数向 GTM 报告事务状态。
  4. 第4组由 GetGIDDataGTM() 和 GetSnapshotGTM() 组成。它们用于从GTM获取事务信息。从 execRemote.c 模块调用 GetGIDDataGTM() 以从 GID 获取 GXID。从 procarray.c 模块调用 GetSnapshotGTM() 以从 GTM 获取事务的快照。在这种情况下,它们不会扫描后端进程数组。请注意,获取的信息的一部分存储到全局变量中并由 procarray.c 模块中的函数使用。例如,GetOldestXmin()使用变量RecentGlobalXmin,该变量保存在快照查询过程中。
 
表2:用于 CN/DN 后端的 GTM 工具函数
函数名
描述
IsGTMConnected()
返回此后端是否有连接到 GTM
InitGTM()
为此后端初始化并建立与 GTM 的连接
CloseGTM()
关闭与 GTM 的连接
BeginTranGTM()
向 GTM 查询新的事务 ID
BeginTranAutovacuumGTM()
查询 用于autovacuum 到 GTM 的新事务 ID
CommitTranGTM()
通知 GTM 提交事务
RollbackTranGTM()
通知 GTM 事务回滚
StartPreparedTranGTM()
通知 GTM 开始准备事务
 
PrepareTranGTM()
通知 GTM 事务准备工作完成
CommitPreparedTranGTM()
通知将准备好的事务提交给 GTM
GetGIDDataGTM()
获取与GID关联的信息,并从GTM获取GXID
GetSnapshotGTM()
从GTM获取事务快照
与上面的 procarray.c 相关,PGXC 调用 KnownAssignedXidsXXXX() 函数来禁用热备用功能。因为双机热备需要为所有datanode提供一致的数据库视图,目前还没有。它们在从机上回放 WAL 记录时的延迟必须不同,并且 PostgreSQL 不提供任何基础设施来同步回放点。这使得为所有从节点提供一致的视图变得极具挑战性,而这对于 Postgres-XC 对从节点的读取事务是必需的。此外,在 slave 中,当前的 KnownAssignedXids 忽略 XLOG_XACT_ASSIGNMENT wal 记录的后半部分以及注册在 wal 记录的前半部分找到的所有可能的 XID。其中一些可能丢失,并且此类丢失的 Xid 保留在缓冲区中,导致缓冲区溢出和 slave 崩溃。
xact.c 中的函数被修改为使用 GXID 和全局快照并处理 PostgresXC 特定的问题。它们列在表 3 中。这些函数是基本事务管理函数的一部分,被执行器、优化器、聚合函数等中的各种函数调用。
CN 需要保存其本地事务和所涉及的远程节点的远程事务的状态。全局事务由在不同节点运行的多个事务组成。它们是单个事务,但从每个节点本地视图的角度来看,它是本地事务的集合。引入结构体 RemoteXactState 来跟踪此全局事务状态。该结构在 src/backend/pgxc/Pool/execRemote.c 内部使用,实现了CN、DN 的内部通信。
 
修改后的事务管理函数如下:
  1. StartTransaction()
将可序列化隔离级别转换为可重复读取。
  1. CommitTransaction()
如果事务涉及 CN 中的数据,则调用PrepareTransaction()准备本地事务。事务准备好后,CN 使用与准备好的事务相同的 GXID 开始新事务,以继续提交序列。然后它调用 PreCommit_Remote() 以 2PC 的方式将提交传播到其他节点。为了在本地处理这个 prepared 事务,它调用 FinishPreparedTransaction()。接下来,它调用CallGTMCallbacks()来通知全局事务正在被提交给回调函数。之后,它会清理各种信息,包括GTM的回调信息、命令ID信息等。最后,AtEOXact_GlobalTxn()请求GTM提交事务,AtEOXact_Remote()清理最后的信息.
  1. AbortTransaction()
CN 调用 PreAbort_Remote() 来中止远程节点上的 prepared 事务,调用 FinishPreparedTransaction() 在本地的 prepared 事务。接下来,它调用 CallGTMCallbacks() 来通知全局事务正在中止。然后它清理各种信息。最后,AtEOXact_GlobalTxn() 请求 GTM 中止事务,AtEOXact_Remote() 清除最后的信息。
  1. RegisterGTMCallback()
在事务开始或停止时注册或取消注册 GTM 的回调函数。这些操作或多或少是事务回调,但我们需要在 HOLD_INTERRUPTS 之前执行它们,因为它是事务管理的一部分,不包含在 xact 清理中。回调在事务完成时被调用,并且可以通过与需要在事务块末尾处理的 GTM 相关的事件进行初始化。
  1. UnregisterGTMCallback()
UnregisterGTMCallback 从回调函数集合中删除指定的函数。
  1. CallGTMCallbacks()
CallGTMCallbacks 调用所有已注册的回调函数来通知事件。
 
CN 需要共享快照。需要维护集群范围的 MVCC。为了在节点之间共享快照,CN 在发送之前使用相同的 libpq 连接将其发送到节点。CN端协议在 pgxcnode.c:pgxc_node_send_snapshot() 中实现。DN 在 postgres.c:PostgresMain() 对其进行处理。 pgxc_node_send_snapshot被公共函数调用,比如execRemote.c:pgxc_start_command_on_connection() 或公共函数,execRemote.c:ExecRemoteUtility()
命令 ID 也会在运行同一事务的后端之间被分解。它是双向的。从CN到 DN 的协议消息在 pgxcnode.c: pgxc_node_send_cmd_id() 中实现,而数据节点对它们的处理在 postgres.c: PostgresMain 中实现。 pgxcnode.c:pgxc_node_send_cmd_id() 被公共函数 execRemtoe.c:pgxc_start_command_on_connection() 调用。如果命令 ID 在任何涉及的 DN 中递增,则会将其报告给 CN。它在 xact.c 中实现:ReportCommandIdChange()。CN 在 pgxc_node.c:handle_response() 处理它。此外,节点必须在事务开始和结束时清除其命令 ID。
GTM 还提供带有新全局事务 ID 的时间戳。它被保存到变量 GTMxactStartTimestamp 中,时间差被保存到变量 GTMdeltaTimestamp 中。为了使用这些时间戳,需要修改表 10.6 中列出的函数。
下面是GTM的内部数据。事务信息结构体如下所示:
 
typedef struct GTM_TransactionInfo { GTM_TransactionHandle gti_handle; uint32 gti_client_id; char gti_global_session_id[GTM_MAX_SESSION_ID_LEN]; bool gti_in_use; GlobalTransactionId gti_gxid; GTM_TransactionStates gti_state; GlobalTransactionId gti_xmin; GTM_IsolationLevel gti_isolevel; bool gti_readonly; GTMProxy_ConnID gti_proxy_client_id; char *nodestring; /* List of nodes prepared */ char *gti_gid; GTM_SnapshotData gti_current_snapshot; bool gti_snapshot_set; GTM_RWLock gti_lock; bool gti_vacuum; gtm_List *gti_created_seqs; gtm_List *gti_dropped_seqs; gtm_List *gti_altered_seqs; } GTM_TransactionInfo;
 
PostgreSQL的快照数据结构如下:
 
typedef struct SnapshotData { SnapshotSatisfiesFunc satisfies; /* tuple test function */ TransactionId xmin; /* all XID < xmin are visible to me */ TransactionId xmax; /* all XID >= xmax are invisible to me */ TransactionId *xip; uint32 xcnt; /* # of xact ids in xip[] */ #ifdef PGXC /* PGXC_COORD */ uint32 max_xcnt; /* Max # of xact in xip[] */ #endif #ifdef __SUPPORT_DISTRIBUTED_TRANSACTION__ GlobalTimestamp start_ts; bool local; /* local snapshot */ TransactionId *prepare_xip; GlobalTimestamp *prepare_xip_ts; uint32 prepare_xcnt; TransactionId *prepare_subxip; GlobalTimestamp *prepare_subxip_ts; uint32 prepare_subxcnt; TransactionId prepare_xmin; int64 number_visible_tuples; int64 scanned_tuples_before_prepare; int64 scanned_tuples_after_prepare; int64 scanned_tuples_after_committed; int64 scanned_tuples_after_abort; #endif ... ... } SnapshotData;
 
GTM的快照数据结构如下:
 
typedef struct GTM_SnapshotData { GlobalTransactionId sn_xmin; GlobalTransactionId sn_xmax; uint32 sn_xcnt; GlobalTransactionId *sn_xip; } GTM_SnapshotData;
 
可以发现 GTM_SnapshotData 和 SnapshotData 非常相似,并且 GTM 在CN 和 DN之外管理相同的数据。但GTM没有子事务和命令ID数据。 GTM 没有子事务数据,因为尚不支持。 GTM 不需要命令 ID 数据,因为它对于启动事务的原始CN来说是本地的。命令 ID 可以在原始CN中本地处理,无需 GTM 的帮助。如果它在涉及的DN或其他CN本地递增,则会通知回 CN 以供以后使用。
 
表5:命令 ID 管理函数
函数
描述
SaveReceivedCommandId()
保存从另一个节点接收到的命令 ID 以供将来使用。
SetReceivedCommandId()
设置从其他节点接收到的命令 ID。
GetReceivedCommandId()
获取从其他节点接收到的命令 ID。
ReportCommandIdChange()
向 CN 报告远程节点当前命令 ID 的变化。这是必需的,因为远程节点可以在触发或约束的情况下增加命令 ID。
IsSendCommandId()
获取命令ID发送状态。如果设置为 true,命令 ID 需要传播到其他节点
SetSendCommandId()
设置命令ID发送状态。如果设置为 true,命令 ID 需要传播到其他节点。
 
表6:处理全局时钟的函数(从原始PG修改后)
函数
AssignTransactionId()
GetCurrentCommandId()
GetCurrentTransactionStartTimestamp()
GetCurrentStatementStartTimestamp()
GetCurrentTransactionStopTimestamp()
RecordTransactionCommit()
RecordTransactionAbort()
StartTransaction()
  1. SPOF 问题的解决方案

GTM 可能是集群中的单点故障。因为任何 DML、DDL 和 DCL 操作的开始都需要新的事务 ID。为了避免这种情况,Postgres-XC提供了GTM slave,以便它可以升级为master,维护所有当前的全局事务和序列状态。
当 GTM 备用数据库启动时,它会连接到主数据库并获取有关事务和序列的所有当前数据。然后 Slave 发送请求将其属性更改为 Standby,断开与GTM Master的原始连接并等待来自GTM Master的连接。master 重新建立与 slave 的连接后,只需将从其他 GTM 客户端接收到的消息传播到具有更改后的消息类型的 slave 以进行备份。表 7 列出了 master 和 slave 之间使用的消息。该表不仅包括事务管理消息,还包括序列管理消息。该列表包括表 1 中列出的所有消息。此表包括非事务性消息。slave 和 master 以相同的方式处理这些消息。不同的是备份消息不需要任何响应。这些特性有助于提高性能,并且可以使大部分源代码在它们之间共享。但是,当 slave 接收到故障转移之前发生故障时,某些备份消息会破坏集群的一致性。表8 列出了此类消息。所以 master 使用SYNC_STANDBY_RESULT消息。处理此类同步消息时,master 将 SYNC_STANDBY_RESULT 发送到该消息之后的 slave。slave 返回对 SYNC_STANDBY_RESULT 的响应。
 
 
  1. 网络瓶颈

由于每个事务控制都需要与GTM交互,因此网络可能会承受繁重的网络工作负载。由于后端进程发送消息是离散的,因此大量的短数据包充斥网络,降低了网络的效率。
为了减轻网络负载,开发者提出GTM Proxy。GTM Proxy 将同类常用消息打包为单个消息,将多个消息打包为单个 TCP 报文段(最大 8kiB),以减少数据包数量。 GTM 代理将 MSG_DATA_FLUSH 附加到打包 TCP 段以进行同步,因为 GTM 必须知道何时在单个 TCP 段中返回打包结果消息。表9 显示了打包的消息。如果每个节点都部署GTM Proxy服务器,它可以打包消息,而不会将数据包泄漏到网络中
表9:打包的事务管理消息
From
To
Description
TXN_BEGIN_GETGXID
TXN_BEGIN_GETGXID_MULTI
启动多个新事务并获取 GXID
TXN_COMMIT
TXN_COMMIT_MULTI
提交多个正在运行或prepared的事务
TXN_ROLLBACK
TXN_ROLLBACK_MULTI
回滚多个事务
SNAPSHOT_GET
SNAPSHOT_GET_MULTI
获取多个全局快照
图1 显示了与 GTM Proxy 交互的示例。线条表示单个消息,其颜色表示消息的类型,数字表示消息和响应 ID。如下图所示:
  1. 如果没有对 GTM 的待处理请求,GTM 代理会快速从后端传播消息。
  2. 如果有对 GTM 的待处理请求,GTM 代理不会从后端传播消息,直到 GTM 返回响应。
  3. 不同类型的消息不会打包成单个消息。
  4. 如果后端有多个待处理消息,GTM 代理会在同一阶段发送它们。
                                                                                         
GTM代理采用 worker 线程模型实现,单线程处理来自后端的多个连接以及到GTM的单个连接。主服务器循环 src/gtm/proxy/proxy_main.c:ServerLoop() 接受来自后端的连接后,该连接将被分派到 proxy_main.c:GTMProxyAddConnection() 中的工作进程。该示例使用一个工作线程。
proxy_main.c:GTMProxy_ThreadMain()是工作线程的主循环。该循环有两个阶段:
  1. 第一阶段从所有后端连接读取数据,并调用 ProcessCommand() 将收到的消息分派给 ProcessXXXXXXXX Command()。如果消息是可打包的,则 ProcessiXXXXXXXX Command() 调用 GTMProxy_CommandPending() 来存储信息。如果消息未打包,则调用 GTMProxy_ProxyCommand() 将消息立即传播到 GTM。请注意,此处不会收到回复。当所有连接都没有待处理数据时,接收到的消息将打包成单个消息,然后将其发送到 GTM。
  2. 第二阶段从 GTM 连接读取数据并调用 ProcessResponse() 将收到的响应分发到后端。重复第二阶段,直到所有响应都与第一阶段收到的消息相对应。
由于 GTM 代理将来自 CN/DN 后端的多个消息分组为单个打包消息,因此需要专门的错误处理。 GTM 协议被扩展来处理这个问题。如果没有 GTM 代理,GTM 可以直接连接到后端。因此GTM自动中止事务来清理连接断开时隐式中止的事务。使用 GTM 代理,即使线程处理的后端连接之一已断开,GTM 代理也会保持连接。为了避免事务被遗弃,某些打包消息包含连接 ID,用于标识接收该消息的连接。 GTM代理发送MSG_BACKEND_DISCONNECT来通知后端断开连接。请注意,MSG_BACKEND_DISCONNECT 消息的正文没有连接 ID。该消息使用 ProxyHdr 通知连接 ID,该连接 ID 由 GTM 代理插入到每个消息的正文中。
 
  1. CN/DN 后端的事务管理

每个 CN/DN 后端都需要连接到GTM以获取全局事务ID(GXID)和全局快照。 src/backend/access/transam 中的 gtm.c 模块负责每个后端和 GTM 之间的连接和通信。本节描述 gtm.c 中定义的函数以及与 CN/DN 后端进程中的 GTM 相关的其他专用事务处理。
  1. gtm.c 模块

gtm.c 模块处理来自协调器/数据节点后端和 gtm/gtm_proxy 的连接和通信。函数定义如下:
  1. IsGTMConnected()
该函数检查与 GTM 的连接是否有效。被以下代码调用:
Caller
File & Description
AtEOXact_GlobalTxn()
xact.c
用于确定事务结束时应使用什么事务ID
  1. CheckConnection()
该函数检查是否已建立与 GTM 的连接。如果没有,它会建立与 GTM 的连接。这是一个静态函数,仅在 gtm.c 内部调用。
  1. InitGTM()
该函数建立与 GTM 的连接,目前仅在 gtm.c 内使用。
  1. CloseGTM()
此函数关闭与 GTM 的连接,被以下代码调用:
Caller
File & Description
PGXCNodeCleanAndRelease()
execRemote.c
当后端结束时调用。
  1. BeginTranGTM()
该函数通知GTM新事务的开始并获取全局事务ID(GXID),被以下代码调用:
Caller
File & Description
GetNewTransactionId()
varsup.c
调用以获取全局事务ID
GetAuxilliaryTransactionId()
xact.c
用于将 auxilliaryTransactionId 条目设置为 CurrentTransactionState
  1. BeginTranAutovacuumGTM()
该函数与 BeginTranGTM() 类似,但仅用于 autovacuum 过程。 autovacuum 进程的 GXID 不会出现在全局快照中。被以下代码调用:
Caller
File & Description
GetNewTransactionId()
varsup.c
在获取 autovacuum 进程的 XID 时调用
  1. CommitTranGTM()
该函数告诉GTM指定的事务已提交并将当前事务ID设置为无效值,被以下代码调用:
Caller
File & Description
AtEOXact_GlobalTxn()
xact.c
在全局事务结束时调用。只有在需要关闭 GTM 上的事务时才调用。
  1. CommitPreparedTranGTM()
该函数告诉 GTM 提交准备好的事务,被以下代码调用:
Caller
File & Description
AtEOXact_GlobalTxn()
xact.c
用于标记全局事务的结束
FinishRemotePreparedTransaction()
execRemote.c
用于在远程节点结束prepared事务
  1. RollbackTranGTM()
该函数告诉 GTM 指定的事务已中止,并将当前事务 ID 设置为无效值,被以下代码调用:
Caller
File & Description
AtEOXact_GlobalTxn()
xact.c
用于标记全局事务的结束
FinishRemotePreparedTransaction()
execRemote.c
用于在远程节点结束prepared事务
  1. StartPreparedTranGTM()
该函数告诉GTM准备事务命令从远程节点开始,被以下代码调用:
Caller
File & Description
PreAbort_Remote()
execRemote.c
中止远程截断
PostPrepare_Remote()
execRemote.c
在远程节点的 post-prepare 中调用
  1. PrepareTranGTM()
该函数告诉GTM准备交易命令已成功,被以下代码调用:
Caller
File & Description
PreAbort_Remote()
 
execRemote.c
在处理 re-abort 时调用
PostPrepare_Remote()
execRemote.c
在处理 post-prepare 时调用
  1. GetGIDDataGTM()
该函数获取GTM内部新的GXID信息、prepared 事务的GXID以及准备过程中涉及的CN/DN 节点列表。暂未使用。
  1. GetSnapshotGTM()
该函数从GTM获取全局快照,被以下代码调用:
Caller
File & Description
GetSnapshotDataDataNode()
 
procarray.c
调用以获取 DN 的快照数据
GetSnapshotDataCoordinator()
procarray.c
调用以获取 CN 的快照数据
  1. CreateSequenceGTM()
该函数在GTM上创建一个序列,被以下代码调用:
Caller
File & Description
DefineSequence()
 
sequence.c
在创建序列时调用
  1. AlterSequenceGTM()
该函数改变 GTM 上的序列,被以下代码调用:
Caller
File & Description
AlterSequence()
sequence.c
调用以修改序列的定义
  1. GetNextValGTM()
该函数获取下一个序列值,被以下代码调用:
Caller
File & Description
nextval_internal()
sequence.c
调用以获取序列的下一个值
  1. SetValGTM()
该函数设置序列的值,被以下代码调用:
Caller
File & Description
do_setval()
sequence.c
这在处理 SETVAL 的 2 和 3 参数形式时被调用
  1. DropSequenceGTM()
此函数根据密钥类型删除序列,被以下代码调用:
Caller
File & Description
drop_sequence_cb()
sequence.c
在序列删除的回调中调用
dropdb()
dbcommands.c
在删除数据库时调用
  1. RenameSequenceGTM()
此函数重命名 GTM 上的序列,被以下代码调用:
Caller
File & Description
RenameRelationInternal()
tablecmds.c
在更改关系名称时调用
AlterTableNamespaceInternal()
tablecmds.c
在将表或 materialized 视图重新定位到另一个名称空间时被调用
AlterSeqNamespaces()
tablecmds.c
调用此函数将指定关系的所有 SERIAL 列序列移动到另一个命名空间
rename_sequence_cb()
sequence.c
序列重命名回调
doRename()
dependency.c
重命名给定对象
  1. RegisterGTM()
该函数将指定节点注册到GTM。用于注册的连接仅在关闭后使用,被以下代码调用:
Caller
File & Description
sigusr1_handler()
postmaster.c
在处理来自子进程的信号条件时调用
  1. UnregisterGTM()
此函数从 GTM 取消注册给定节点。用于注册的连接仅在关闭后使用。被以下代码调用:
Caller
File & Description
pmdie()
postmaster.c
在信号处理程序中调用以处理各种 postmaster 信号
sigusr1_handler()
postmaster.c
在处理来自子进程的信号条件时调用
  1. ReportBarrierGTM()
该函数向 GTM 报告障碍。这用于备份给定屏障 ID 的 GTM 重启点。
Caller
File & Description
RequestBarrier()
barrier.c
在处理 CREATE BARRIER 语句时调用
  1. xact.c 模块

该模块包括 Postgres-XC 特定函数:
  1. RegisterTransactionLocalNode()
标记本地节点是否已完成某些写入活动。
Caller
File & Description
ExecRemoteUtility()
execRemote.c
  1. ForgetTransactionLocalNode()
遗忘本地节点参与的事务
Caller
File & Description
CommitTransaction()
xact.c
PrepareTransaction()
xact.c
AbortTransaction()
xact.c
  1. IsTransactionLocalNode()
检查本地节点是否参与事务。暂未被调用。
  1. IsXidImplicit()
检查给定的 xid 是否用于隐式 2PC。
Caller
File & Description
standard_ProcessUtility()
utility.c
在处理 PREPARE TRANSACTION 命令时调用
 
 
0条评论
0 / 1000
a****n
3文章数
2粉丝数
a****n
3 文章 | 2 粉丝
a****n
3文章数
2粉丝数
a****n
3 文章 | 2 粉丝
原创

Tbase 分布式事务原理与源码

2023-08-28 03:39:24
92
0
  1. 全局 MVCC

PGXC的事务管理需要满足ACID,并确保集群中多节点读取事务的原子性。此功能通过MVCC实现。Postgres-XC 基本上使用 src/backend/utils/time/tqual.c 中实现的 PostgreSQL MVCC 机制:通过 xmin、xmax、CLOG 和事务快照检查可见性(有时包括 cmin 和 cmax)。Postgres-XC 只是扩展了 PostgreSQL 分配事务 ID 并将快照提供给全局。提供全局事务信息的外部组件称为全局事务管理器 (GTM),集群范围的 MVCC 依赖GTM实现。GTM与 CN 和DN 的分开实现。GTM的源代码在src/gtm/main 中。
 
当用户向 CN 发出 DML 语句时,CN 从GTM获取全局事务ID(GXID)和全局事务快照并将其发送到 DN。DN 使用 GXID 和来自 CN 的快照来操作其数据库。通过这种方式,DN 共享相同的事务上下文,并且事务在多个 CN 和 DN 中运行时可以保持原子性和统一的可见性。在事务结束时,如果多个节点参与更新,CN 会使用 2PC 协议隐式提交事务。通过跟踪全局事务状态,CN 向 GTM 报告全局事务状态。
 
可见性检查有时使用 CN 生成的本地事务命令 ID。在发送每个命令之前,它也会发送到 DN 。如果命令 ID 在某些涉及的 DN中本地提前接收到,它们会将更改通知给 CN。
 
PGXC 支持 PostgreSQL 中实现的所有事务隔离级别。如果事务隔离级别是REPEATABLE READ,则在整个事务中将获取并使用一个快照。如果隔离模式是 READ COMMITTED,CN 会获取每个语句的最新快照。如果 Planner 将一条语句分为多个语句,则此快照将用于多个语句。
 
需要进行一些小的更改才能使此全局 MVCC 与现有 PostgreSQL 代码一起运行。例如,CLOG扩展算法需要一些修改。在全局事务中,有些节点可能不参与,并且在这些节点中缺少该事务的GXID。 CLOG 需要一个扩展来处理这个缺失的 GXID,以使 CLOG 扩展正常工作,相关代码实现在src/backend/access/transam/clog.c:ExpandCLOG()。
 
  1. GTM

CN 在以下情况中与GTM进行通信
  1. CN 请求新的事务 ID
  2. CN 需要新的事务快照
  3. CN 提交或 abort 事务
DN只有在执行 vacuum 的时候与 GTM 通信。
下表列出了 GTM 和其他节点(CN, DN)之间用于全局事务管理的消息。此表显示了在 GTM 和 CN/DN 后端中实际实现的消息,不包括仅在 GTM 中实现但未真正使用的消息。
表1:事务控制消息
消息名
描述
TXN_BEGIN_GETGXID
开始一个新事务并获取 GXID
TXN_START_PREPARED
开始准备将要提交的事务
TXN_COMMIT
提交一个 running 或 prepared 的事务
TXN_COMMIT_PREPARED
提交一个 prepared 的事务
TXN_PREPARE
结束 preparing 一个事务
TXN_ROLLBACK
回滚一个事务
TXN_GET_GID_DATA
根据 GID 获取相关信息以及 GXID
SNAPSHOT_GET
获取全局快照
TXN_BEGIN_GETGXID_AUTOVACUUM
开始新事务并获取 GXID 用于自动vacuum
GTM客户端使用的实际协议在src/gtm/client/gtm_client.c中实现,这个原生实现无法从 CN/DN 后端调用。Utility函数作为这些原始实现的快捷方式在 src/backend/access/transam/gtm.c 中实现,如表2所示,GTM的工具函数分为四种:
  1. 它们处理与 GTM 的连接。这些函数被 gtm.c 内部的其他utility函数调用。InitGTM() 建立与 GTM 的连接并将连接信息存储到进程本地内存。该函数在内部调用 InitGTM(),并使用已保存的连接。 CloseGTM() 重置已保存的连接和信息。
  2. 向 GTM 查询新的全局事务 ID。这些函数被 varsup.c 中的函数调用,这些函数负责 OID 和 XID 变量支持。 varsup.c 中的函数使用上述的函数,而不是原始的本地 XID feed机制。
  3. 它们用于控制事务,被 xact.c 和 execRemote.c 中的函数调用。 xact.c 中的函数被修改为使用这些工具函数向 GTM 报告事务状态。
  4. 第4组由 GetGIDDataGTM() 和 GetSnapshotGTM() 组成。它们用于从GTM获取事务信息。从 execRemote.c 模块调用 GetGIDDataGTM() 以从 GID 获取 GXID。从 procarray.c 模块调用 GetSnapshotGTM() 以从 GTM 获取事务的快照。在这种情况下,它们不会扫描后端进程数组。请注意,获取的信息的一部分存储到全局变量中并由 procarray.c 模块中的函数使用。例如,GetOldestXmin()使用变量RecentGlobalXmin,该变量保存在快照查询过程中。
 
表2:用于 CN/DN 后端的 GTM 工具函数
函数名
描述
IsGTMConnected()
返回此后端是否有连接到 GTM
InitGTM()
为此后端初始化并建立与 GTM 的连接
CloseGTM()
关闭与 GTM 的连接
BeginTranGTM()
向 GTM 查询新的事务 ID
BeginTranAutovacuumGTM()
查询 用于autovacuum 到 GTM 的新事务 ID
CommitTranGTM()
通知 GTM 提交事务
RollbackTranGTM()
通知 GTM 事务回滚
StartPreparedTranGTM()
通知 GTM 开始准备事务
 
PrepareTranGTM()
通知 GTM 事务准备工作完成
CommitPreparedTranGTM()
通知将准备好的事务提交给 GTM
GetGIDDataGTM()
获取与GID关联的信息,并从GTM获取GXID
GetSnapshotGTM()
从GTM获取事务快照
与上面的 procarray.c 相关,PGXC 调用 KnownAssignedXidsXXXX() 函数来禁用热备用功能。因为双机热备需要为所有datanode提供一致的数据库视图,目前还没有。它们在从机上回放 WAL 记录时的延迟必须不同,并且 PostgreSQL 不提供任何基础设施来同步回放点。这使得为所有从节点提供一致的视图变得极具挑战性,而这对于 Postgres-XC 对从节点的读取事务是必需的。此外,在 slave 中,当前的 KnownAssignedXids 忽略 XLOG_XACT_ASSIGNMENT wal 记录的后半部分以及注册在 wal 记录的前半部分找到的所有可能的 XID。其中一些可能丢失,并且此类丢失的 Xid 保留在缓冲区中,导致缓冲区溢出和 slave 崩溃。
xact.c 中的函数被修改为使用 GXID 和全局快照并处理 PostgresXC 特定的问题。它们列在表 3 中。这些函数是基本事务管理函数的一部分,被执行器、优化器、聚合函数等中的各种函数调用。
CN 需要保存其本地事务和所涉及的远程节点的远程事务的状态。全局事务由在不同节点运行的多个事务组成。它们是单个事务,但从每个节点本地视图的角度来看,它是本地事务的集合。引入结构体 RemoteXactState 来跟踪此全局事务状态。该结构在 src/backend/pgxc/Pool/execRemote.c 内部使用,实现了CN、DN 的内部通信。
 
修改后的事务管理函数如下:
  1. StartTransaction()
将可序列化隔离级别转换为可重复读取。
  1. CommitTransaction()
如果事务涉及 CN 中的数据,则调用PrepareTransaction()准备本地事务。事务准备好后,CN 使用与准备好的事务相同的 GXID 开始新事务,以继续提交序列。然后它调用 PreCommit_Remote() 以 2PC 的方式将提交传播到其他节点。为了在本地处理这个 prepared 事务,它调用 FinishPreparedTransaction()。接下来,它调用CallGTMCallbacks()来通知全局事务正在被提交给回调函数。之后,它会清理各种信息,包括GTM的回调信息、命令ID信息等。最后,AtEOXact_GlobalTxn()请求GTM提交事务,AtEOXact_Remote()清理最后的信息.
  1. AbortTransaction()
CN 调用 PreAbort_Remote() 来中止远程节点上的 prepared 事务,调用 FinishPreparedTransaction() 在本地的 prepared 事务。接下来,它调用 CallGTMCallbacks() 来通知全局事务正在中止。然后它清理各种信息。最后,AtEOXact_GlobalTxn() 请求 GTM 中止事务,AtEOXact_Remote() 清除最后的信息。
  1. RegisterGTMCallback()
在事务开始或停止时注册或取消注册 GTM 的回调函数。这些操作或多或少是事务回调,但我们需要在 HOLD_INTERRUPTS 之前执行它们,因为它是事务管理的一部分,不包含在 xact 清理中。回调在事务完成时被调用,并且可以通过与需要在事务块末尾处理的 GTM 相关的事件进行初始化。
  1. UnregisterGTMCallback()
UnregisterGTMCallback 从回调函数集合中删除指定的函数。
  1. CallGTMCallbacks()
CallGTMCallbacks 调用所有已注册的回调函数来通知事件。
 
CN 需要共享快照。需要维护集群范围的 MVCC。为了在节点之间共享快照,CN 在发送之前使用相同的 libpq 连接将其发送到节点。CN端协议在 pgxcnode.c:pgxc_node_send_snapshot() 中实现。DN 在 postgres.c:PostgresMain() 对其进行处理。 pgxc_node_send_snapshot被公共函数调用,比如execRemote.c:pgxc_start_command_on_connection() 或公共函数,execRemote.c:ExecRemoteUtility()
命令 ID 也会在运行同一事务的后端之间被分解。它是双向的。从CN到 DN 的协议消息在 pgxcnode.c: pgxc_node_send_cmd_id() 中实现,而数据节点对它们的处理在 postgres.c: PostgresMain 中实现。 pgxcnode.c:pgxc_node_send_cmd_id() 被公共函数 execRemtoe.c:pgxc_start_command_on_connection() 调用。如果命令 ID 在任何涉及的 DN 中递增,则会将其报告给 CN。它在 xact.c 中实现:ReportCommandIdChange()。CN 在 pgxc_node.c:handle_response() 处理它。此外,节点必须在事务开始和结束时清除其命令 ID。
GTM 还提供带有新全局事务 ID 的时间戳。它被保存到变量 GTMxactStartTimestamp 中,时间差被保存到变量 GTMdeltaTimestamp 中。为了使用这些时间戳,需要修改表 10.6 中列出的函数。
下面是GTM的内部数据。事务信息结构体如下所示:
 
typedef struct GTM_TransactionInfo { GTM_TransactionHandle gti_handle; uint32 gti_client_id; char gti_global_session_id[GTM_MAX_SESSION_ID_LEN]; bool gti_in_use; GlobalTransactionId gti_gxid; GTM_TransactionStates gti_state; GlobalTransactionId gti_xmin; GTM_IsolationLevel gti_isolevel; bool gti_readonly; GTMProxy_ConnID gti_proxy_client_id; char *nodestring; /* List of nodes prepared */ char *gti_gid; GTM_SnapshotData gti_current_snapshot; bool gti_snapshot_set; GTM_RWLock gti_lock; bool gti_vacuum; gtm_List *gti_created_seqs; gtm_List *gti_dropped_seqs; gtm_List *gti_altered_seqs; } GTM_TransactionInfo;
 
PostgreSQL的快照数据结构如下:
 
typedef struct SnapshotData { SnapshotSatisfiesFunc satisfies; /* tuple test function */ TransactionId xmin; /* all XID < xmin are visible to me */ TransactionId xmax; /* all XID >= xmax are invisible to me */ TransactionId *xip; uint32 xcnt; /* # of xact ids in xip[] */ #ifdef PGXC /* PGXC_COORD */ uint32 max_xcnt; /* Max # of xact in xip[] */ #endif #ifdef __SUPPORT_DISTRIBUTED_TRANSACTION__ GlobalTimestamp start_ts; bool local; /* local snapshot */ TransactionId *prepare_xip; GlobalTimestamp *prepare_xip_ts; uint32 prepare_xcnt; TransactionId *prepare_subxip; GlobalTimestamp *prepare_subxip_ts; uint32 prepare_subxcnt; TransactionId prepare_xmin; int64 number_visible_tuples; int64 scanned_tuples_before_prepare; int64 scanned_tuples_after_prepare; int64 scanned_tuples_after_committed; int64 scanned_tuples_after_abort; #endif ... ... } SnapshotData;
 
GTM的快照数据结构如下:
 
typedef struct GTM_SnapshotData { GlobalTransactionId sn_xmin; GlobalTransactionId sn_xmax; uint32 sn_xcnt; GlobalTransactionId *sn_xip; } GTM_SnapshotData;
 
可以发现 GTM_SnapshotData 和 SnapshotData 非常相似,并且 GTM 在CN 和 DN之外管理相同的数据。但GTM没有子事务和命令ID数据。 GTM 没有子事务数据,因为尚不支持。 GTM 不需要命令 ID 数据,因为它对于启动事务的原始CN来说是本地的。命令 ID 可以在原始CN中本地处理,无需 GTM 的帮助。如果它在涉及的DN或其他CN本地递增,则会通知回 CN 以供以后使用。
 
表5:命令 ID 管理函数
函数
描述
SaveReceivedCommandId()
保存从另一个节点接收到的命令 ID 以供将来使用。
SetReceivedCommandId()
设置从其他节点接收到的命令 ID。
GetReceivedCommandId()
获取从其他节点接收到的命令 ID。
ReportCommandIdChange()
向 CN 报告远程节点当前命令 ID 的变化。这是必需的,因为远程节点可以在触发或约束的情况下增加命令 ID。
IsSendCommandId()
获取命令ID发送状态。如果设置为 true,命令 ID 需要传播到其他节点
SetSendCommandId()
设置命令ID发送状态。如果设置为 true,命令 ID 需要传播到其他节点。
 
表6:处理全局时钟的函数(从原始PG修改后)
函数
AssignTransactionId()
GetCurrentCommandId()
GetCurrentTransactionStartTimestamp()
GetCurrentStatementStartTimestamp()
GetCurrentTransactionStopTimestamp()
RecordTransactionCommit()
RecordTransactionAbort()
StartTransaction()
  1. SPOF 问题的解决方案

GTM 可能是集群中的单点故障。因为任何 DML、DDL 和 DCL 操作的开始都需要新的事务 ID。为了避免这种情况,Postgres-XC提供了GTM slave,以便它可以升级为master,维护所有当前的全局事务和序列状态。
当 GTM 备用数据库启动时,它会连接到主数据库并获取有关事务和序列的所有当前数据。然后 Slave 发送请求将其属性更改为 Standby,断开与GTM Master的原始连接并等待来自GTM Master的连接。master 重新建立与 slave 的连接后,只需将从其他 GTM 客户端接收到的消息传播到具有更改后的消息类型的 slave 以进行备份。表 7 列出了 master 和 slave 之间使用的消息。该表不仅包括事务管理消息,还包括序列管理消息。该列表包括表 1 中列出的所有消息。此表包括非事务性消息。slave 和 master 以相同的方式处理这些消息。不同的是备份消息不需要任何响应。这些特性有助于提高性能,并且可以使大部分源代码在它们之间共享。但是,当 slave 接收到故障转移之前发生故障时,某些备份消息会破坏集群的一致性。表8 列出了此类消息。所以 master 使用SYNC_STANDBY_RESULT消息。处理此类同步消息时,master 将 SYNC_STANDBY_RESULT 发送到该消息之后的 slave。slave 返回对 SYNC_STANDBY_RESULT 的响应。
 
 
  1. 网络瓶颈

由于每个事务控制都需要与GTM交互,因此网络可能会承受繁重的网络工作负载。由于后端进程发送消息是离散的,因此大量的短数据包充斥网络,降低了网络的效率。
为了减轻网络负载,开发者提出GTM Proxy。GTM Proxy 将同类常用消息打包为单个消息,将多个消息打包为单个 TCP 报文段(最大 8kiB),以减少数据包数量。 GTM 代理将 MSG_DATA_FLUSH 附加到打包 TCP 段以进行同步,因为 GTM 必须知道何时在单个 TCP 段中返回打包结果消息。表9 显示了打包的消息。如果每个节点都部署GTM Proxy服务器,它可以打包消息,而不会将数据包泄漏到网络中
表9:打包的事务管理消息
From
To
Description
TXN_BEGIN_GETGXID
TXN_BEGIN_GETGXID_MULTI
启动多个新事务并获取 GXID
TXN_COMMIT
TXN_COMMIT_MULTI
提交多个正在运行或prepared的事务
TXN_ROLLBACK
TXN_ROLLBACK_MULTI
回滚多个事务
SNAPSHOT_GET
SNAPSHOT_GET_MULTI
获取多个全局快照
图1 显示了与 GTM Proxy 交互的示例。线条表示单个消息,其颜色表示消息的类型,数字表示消息和响应 ID。如下图所示:
  1. 如果没有对 GTM 的待处理请求,GTM 代理会快速从后端传播消息。
  2. 如果有对 GTM 的待处理请求,GTM 代理不会从后端传播消息,直到 GTM 返回响应。
  3. 不同类型的消息不会打包成单个消息。
  4. 如果后端有多个待处理消息,GTM 代理会在同一阶段发送它们。
                                                                                         
GTM代理采用 worker 线程模型实现,单线程处理来自后端的多个连接以及到GTM的单个连接。主服务器循环 src/gtm/proxy/proxy_main.c:ServerLoop() 接受来自后端的连接后,该连接将被分派到 proxy_main.c:GTMProxyAddConnection() 中的工作进程。该示例使用一个工作线程。
proxy_main.c:GTMProxy_ThreadMain()是工作线程的主循环。该循环有两个阶段:
  1. 第一阶段从所有后端连接读取数据,并调用 ProcessCommand() 将收到的消息分派给 ProcessXXXXXXXX Command()。如果消息是可打包的,则 ProcessiXXXXXXXX Command() 调用 GTMProxy_CommandPending() 来存储信息。如果消息未打包,则调用 GTMProxy_ProxyCommand() 将消息立即传播到 GTM。请注意,此处不会收到回复。当所有连接都没有待处理数据时,接收到的消息将打包成单个消息,然后将其发送到 GTM。
  2. 第二阶段从 GTM 连接读取数据并调用 ProcessResponse() 将收到的响应分发到后端。重复第二阶段,直到所有响应都与第一阶段收到的消息相对应。
由于 GTM 代理将来自 CN/DN 后端的多个消息分组为单个打包消息,因此需要专门的错误处理。 GTM 协议被扩展来处理这个问题。如果没有 GTM 代理,GTM 可以直接连接到后端。因此GTM自动中止事务来清理连接断开时隐式中止的事务。使用 GTM 代理,即使线程处理的后端连接之一已断开,GTM 代理也会保持连接。为了避免事务被遗弃,某些打包消息包含连接 ID,用于标识接收该消息的连接。 GTM代理发送MSG_BACKEND_DISCONNECT来通知后端断开连接。请注意,MSG_BACKEND_DISCONNECT 消息的正文没有连接 ID。该消息使用 ProxyHdr 通知连接 ID,该连接 ID 由 GTM 代理插入到每个消息的正文中。
 
  1. CN/DN 后端的事务管理

每个 CN/DN 后端都需要连接到GTM以获取全局事务ID(GXID)和全局快照。 src/backend/access/transam 中的 gtm.c 模块负责每个后端和 GTM 之间的连接和通信。本节描述 gtm.c 中定义的函数以及与 CN/DN 后端进程中的 GTM 相关的其他专用事务处理。
  1. gtm.c 模块

gtm.c 模块处理来自协调器/数据节点后端和 gtm/gtm_proxy 的连接和通信。函数定义如下:
  1. IsGTMConnected()
该函数检查与 GTM 的连接是否有效。被以下代码调用:
Caller
File & Description
AtEOXact_GlobalTxn()
xact.c
用于确定事务结束时应使用什么事务ID
  1. CheckConnection()
该函数检查是否已建立与 GTM 的连接。如果没有,它会建立与 GTM 的连接。这是一个静态函数,仅在 gtm.c 内部调用。
  1. InitGTM()
该函数建立与 GTM 的连接,目前仅在 gtm.c 内使用。
  1. CloseGTM()
此函数关闭与 GTM 的连接,被以下代码调用:
Caller
File & Description
PGXCNodeCleanAndRelease()
execRemote.c
当后端结束时调用。
  1. BeginTranGTM()
该函数通知GTM新事务的开始并获取全局事务ID(GXID),被以下代码调用:
Caller
File & Description
GetNewTransactionId()
varsup.c
调用以获取全局事务ID
GetAuxilliaryTransactionId()
xact.c
用于将 auxilliaryTransactionId 条目设置为 CurrentTransactionState
  1. BeginTranAutovacuumGTM()
该函数与 BeginTranGTM() 类似,但仅用于 autovacuum 过程。 autovacuum 进程的 GXID 不会出现在全局快照中。被以下代码调用:
Caller
File & Description
GetNewTransactionId()
varsup.c
在获取 autovacuum 进程的 XID 时调用
  1. CommitTranGTM()
该函数告诉GTM指定的事务已提交并将当前事务ID设置为无效值,被以下代码调用:
Caller
File & Description
AtEOXact_GlobalTxn()
xact.c
在全局事务结束时调用。只有在需要关闭 GTM 上的事务时才调用。
  1. CommitPreparedTranGTM()
该函数告诉 GTM 提交准备好的事务,被以下代码调用:
Caller
File & Description
AtEOXact_GlobalTxn()
xact.c
用于标记全局事务的结束
FinishRemotePreparedTransaction()
execRemote.c
用于在远程节点结束prepared事务
  1. RollbackTranGTM()
该函数告诉 GTM 指定的事务已中止,并将当前事务 ID 设置为无效值,被以下代码调用:
Caller
File & Description
AtEOXact_GlobalTxn()
xact.c
用于标记全局事务的结束
FinishRemotePreparedTransaction()
execRemote.c
用于在远程节点结束prepared事务
  1. StartPreparedTranGTM()
该函数告诉GTM准备事务命令从远程节点开始,被以下代码调用:
Caller
File & Description
PreAbort_Remote()
execRemote.c
中止远程截断
PostPrepare_Remote()
execRemote.c
在远程节点的 post-prepare 中调用
  1. PrepareTranGTM()
该函数告诉GTM准备交易命令已成功,被以下代码调用:
Caller
File & Description
PreAbort_Remote()
 
execRemote.c
在处理 re-abort 时调用
PostPrepare_Remote()
execRemote.c
在处理 post-prepare 时调用
  1. GetGIDDataGTM()
该函数获取GTM内部新的GXID信息、prepared 事务的GXID以及准备过程中涉及的CN/DN 节点列表。暂未使用。
  1. GetSnapshotGTM()
该函数从GTM获取全局快照,被以下代码调用:
Caller
File & Description
GetSnapshotDataDataNode()
 
procarray.c
调用以获取 DN 的快照数据
GetSnapshotDataCoordinator()
procarray.c
调用以获取 CN 的快照数据
  1. CreateSequenceGTM()
该函数在GTM上创建一个序列,被以下代码调用:
Caller
File & Description
DefineSequence()
 
sequence.c
在创建序列时调用
  1. AlterSequenceGTM()
该函数改变 GTM 上的序列,被以下代码调用:
Caller
File & Description
AlterSequence()
sequence.c
调用以修改序列的定义
  1. GetNextValGTM()
该函数获取下一个序列值,被以下代码调用:
Caller
File & Description
nextval_internal()
sequence.c
调用以获取序列的下一个值
  1. SetValGTM()
该函数设置序列的值,被以下代码调用:
Caller
File & Description
do_setval()
sequence.c
这在处理 SETVAL 的 2 和 3 参数形式时被调用
  1. DropSequenceGTM()
此函数根据密钥类型删除序列,被以下代码调用:
Caller
File & Description
drop_sequence_cb()
sequence.c
在序列删除的回调中调用
dropdb()
dbcommands.c
在删除数据库时调用
  1. RenameSequenceGTM()
此函数重命名 GTM 上的序列,被以下代码调用:
Caller
File & Description
RenameRelationInternal()
tablecmds.c
在更改关系名称时调用
AlterTableNamespaceInternal()
tablecmds.c
在将表或 materialized 视图重新定位到另一个名称空间时被调用
AlterSeqNamespaces()
tablecmds.c
调用此函数将指定关系的所有 SERIAL 列序列移动到另一个命名空间
rename_sequence_cb()
sequence.c
序列重命名回调
doRename()
dependency.c
重命名给定对象
  1. RegisterGTM()
该函数将指定节点注册到GTM。用于注册的连接仅在关闭后使用,被以下代码调用:
Caller
File & Description
sigusr1_handler()
postmaster.c
在处理来自子进程的信号条件时调用
  1. UnregisterGTM()
此函数从 GTM 取消注册给定节点。用于注册的连接仅在关闭后使用。被以下代码调用:
Caller
File & Description
pmdie()
postmaster.c
在信号处理程序中调用以处理各种 postmaster 信号
sigusr1_handler()
postmaster.c
在处理来自子进程的信号条件时调用
  1. ReportBarrierGTM()
该函数向 GTM 报告障碍。这用于备份给定屏障 ID 的 GTM 重启点。
Caller
File & Description
RequestBarrier()
barrier.c
在处理 CREATE BARRIER 语句时调用
  1. xact.c 模块

该模块包括 Postgres-XC 特定函数:
  1. RegisterTransactionLocalNode()
标记本地节点是否已完成某些写入活动。
Caller
File & Description
ExecRemoteUtility()
execRemote.c
  1. ForgetTransactionLocalNode()
遗忘本地节点参与的事务
Caller
File & Description
CommitTransaction()
xact.c
PrepareTransaction()
xact.c
AbortTransaction()
xact.c
  1. IsTransactionLocalNode()
检查本地节点是否参与事务。暂未被调用。
  1. IsXidImplicit()
检查给定的 xid 是否用于隐式 2PC。
Caller
File & Description
standard_ProcessUtility()
utility.c
在处理 PREPARE TRANSACTION 命令时调用
 
 
文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0