openGauss源码解析(75)
openGauss源码解析:事务机制源码解析(6)
5.2.4 进程内多线程管理机制
简述进程内多线程管理机制相关数据结构及多版本快照计算机制。
1. 事务信息管理
数据库启动时候维护了一段共享内存,每个线程初始化的时候会从这个共享内存中获取一个槽位并将其线程信息记录到槽位中。获取快照时,需要在共享内存数组中更新槽位信息,事务结束时,需要从槽位中将其事务信息清除。计算快照时,通过遍历该全局数组,获取当前所有并发线程的事务信息,并计算出快照信息(xmin、xmax、snapshotcsn等)。事务信息管理的关键数据结构代码如下:
typedef struct PGXACT {
GTM_TransactionHandle handle; /* 单机模式无用参数 */
TransactionId xid; /* 该线程持有的xid号,如果没有则为0 */
TransactionId prepare_xid; /* 准备阶段的xid号*/
TransactionId xmin; /* 当前事务开启时最小的活跃xid,vaccum操作不会删除那些xid大于等于xmin的元组。 */
CommitSeqNo csn_min; /* 当前事务开启时最小的活跃CSN号*/
TransactionId next_xid; /* 单机模式无用参数*/
int nxids; /* 子事物个数*/
uint8 vacuumFlags; /* vacuum操作相关的flag */
bool needToSyncXid; /* 单机模式无用参数*/
bool delayChkpt; /* 如果该线程需要checkpoint线程延迟等待,此值为true
#ifdef __aarch64__ */
char padding[PG_CACHE_LINE_SIZE - PGXACT_PAD_OFFSET]; /* 为了性能考虑的结构体对齐*/
#endif
} PGXACT;
struct PGPROC {
SHM_QUEUE links; /* 链表中的指针 */
PGSemaphoreData sem; /* 休眠等待的信号量 */
int waitStatus; /* 等待状态 */
Latch procLatch; /* 线程的通用闩锁 */
LocalTransactionId lxid; /* 当前线程本地顶层事务ID */
ThreadId pid; /* 线程的PID */
ThreadId sessMemorySessionid;
uint64 sessionid; /* 线程池模式下当前的会话ID */
int logictid; /* 逻辑线程ID */
TransactionId gtt_session_frozenxid; /* 会话级全局临时表的冻结XID */
int pgprocno;
int nodeno;
/* 线程启动时下面这些数据结构为0 */
BackendId backendId; /* 线程的后台ID */
Oid databaseId; /* 当前访问数据库的OID */
Oid roleId; /* 当前用户的OID */
/* 版本号,用于升级过程中新老版本的判断 */
uint32 workingVersionNum;
/*热备模式下,标记当前事务是否收到冲突信号。设置该值时需要持有ProcArray锁。 */
bool recoveryConflictPending;
/* 线程等待的轻量级锁信息. */
bool lwWaiting; /* 当等待轻量级锁时,为真 */
uint8 lwWaitMode; /* 预获取锁的模式 */
bool lwIsVictim; /* 强制放弃轻量级锁 */
dlist_node lwWaitLink; /* 等待在相同轻量级锁对象的下一个等待者 */
/* 线程等待的常规锁信息 */
LOCK* waitLock; /* 等待的常规锁对象 */
PROCLOCK* waitProcLock; /* 等待常规锁对象的持有者 */
LOCKMODE waitLockMode; /* 预获取常规锁对象的模式 */
LOCKMASK heldLocks; /* 本线程获取锁对象模式的位掩码 */
/* 等待主备机回放日志同步的信息 */
XLogRecPtr waitLSN; /* 等待的lsn*/
int syncRepState; /* 等待主备同步的状态 */
bool syncRepInCompleteQueue; /* 是否等待在完成队列中 */
SHM_QUEUE syncRepLinks; /* 指向同步队列的指针 */
DataQueuePtr waitDataSyncPoint; /* 数据页复制的数据同步点 */
int dataSyncRepState; /* 数据页复制的同步状态 */
SHM_QUEUE dataSyncRepLinks; /* 指向数据页同步队列的指针*/
MemoryContext topmcxt; /* 本线程的顶层内存上下文 */
char myProgName[64];
pg_time_t myStartTime;
syscalllock deleMemContextMutex;
SHM_QUEUE myProcLocks[NUM_LOCK_PARTITIONS];
/* 以下结构为了实现XID批量提交 */
/* 是否为XID批量提交中的成员 */
bool procArrayGroupMember;
/* XID批量提交中的下一个成员 */
pg_atomic_uint32 procArrayGroupNext;
/* 父事务XID和子事物XID中的最大者 */
TransactionId procArrayGroupMemberXid;
/* 提交序列号 */
CommitSeqNo commitCSN;
/* 以下结构为了实现CLOG批量提交 */
bool clogGroupMember; /* 是否为CLOG批量提交中的成员*/
pg_atomic_uint32 clogGroupNext; /* CLOG批量提交中的下一个成员*/
TransactionId clogGroupMemberXid; /* CLOG批量提交的事务ID */
CLogXidStatus clogGroupMemberXidStatus; /* CLOG批量提交的事务状态 */
int64 clogGroupMemberPage; /* CLOG批量提交对应的CLOG页面 */
XLogRecPtr clogGroupMemberLsn; /* CLOG批量提交成员的提交回放日志位置 */
#ifdef __aarch64__
/* 以下结构体是为了实现ARM架构下回放日志批量插入 */
bool xlogGroupMember;
pg_atomic_uint32 xlogGroupNext;
XLogRecData* xlogGrouprdata;
XLogRecPtr xlogGroupfpw_lsn;
XLogRecPtr* xlogGroupProcLastRecPtr;
XLogRecPtr* xlogGroupXactLastRecEnd;
void* xlogGroupCurrentTransactionState;
XLogRecPtr* xlogGroupRedoRecPtr;
void* xlogGroupLogwrtResult;
XLogRecPtr xlogGroupReturntRecPtr;
TimeLineID xlogGroupTimeLineID;
bool* xlogGroupDoPageWrites;
bool xlogGroupIsFPW;
uint64 snap_refcnt_bitmap;
#endif
LWLock* subxidsLock;
struct XidCache subxids; /* 子事物XID */
LWLock* backendLock; /* 每个线程的轻量级锁,用于保护以下数据结构的并发访问 */
/* Lock manager data, recording fast-path locks taken by this backend. */
uint64 fpLockBits; /* 快速路径锁的持有模式 */
FastPathTag fpRelId[FP_LOCK_SLOTS_PER_BACKEND]; /* 表对象的槽位 */
bool fpVXIDLock; /* 是否获得本地XID的快速路径锁 */
LocalTransactionId fpLocalTransactionId; /* 本地的XID */
};

图5-15 事务信息
如图5-15所示,proc_base_all_procs以及proc_base_all_xacts为全局的共享区域,每个线程启动的时候会在这个共享区域中注册一个槽位,并且将线程级指针变量t_thrd.proc以及t_thrd.pgxact指向该区域。当该线程有事务开始时,会将对应事务的xmin、xid等信息填写到pgxact结构体中。关键函数及接口如下。

浙公网安备 33010602011771号