
本文中涉及到的代码版本是Greenplum 6X的稳定分支(greenplum-db/gpdb at 6X_STABLE (github.com)),其他分支上(如master,5X等)的代码逻辑会有所差异,请读者留意。

快照基础
xmin,创建这个元组的事务id(txid) xmax,删除这个元组的事务id
insert, set xmin=txid_current,set xmax=0 delete, set xmax=txid_current update = delete + insert
而快照如其名字,是在一个特定的时刻对系统当前各个事务的运行状态的一个拍摄。其格式可以表示为: xmin : xmax : xip_list (,分割),见如下示例:
demo=# begin;BEGINdemo=# select txid_current();txid_current--------------3911(1 row)demo=# select txid_current_snapshot();txid_current_snapshot-----------------------3911:3915:3912,3913(1 row)
xmin,最早还在活跃的txid,所有txid < 它的事务都已经结束了(提交或者回滚) xmax,下一个要分配的txid,所有txid >= 它的事务尚未开始(即它的操作对此快照不可见) xip_list,xmin和xmax之间的活跃txid

快照相关函数
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[] */… // 暂时省略掉其他字段}
heap_fetch(){/*宏的实现:调用satisfies指向的可见性函数#define HeapTupleSatisfiesVisibility(rel, tuple, snapshot, buffer) \((*(snapshot)->satisfies) (rel, tuple, snapshot, buffer))*/valid = HeapTupleSatisfiesVisibility(relation, tuple, snapshot, buffer);…if (valid) return true; // 找到了可见的元组…return false;}

获得快照的时机
读已提交(RC),对于事务中每条语句,都生成一个新的快照数据 可重复读(RR),只有事务的第一条语句才生成快照数据,随后的语句只复用这个快照数据。
exec_simple_query(){…/** Set up a snapshot if parse analysis/planning will need one.*/// 某些类型query在planner阶段也需要获取快照if (analyze_requires_snapshot(parsetree)){PushActiveSnapshot(GetTransactionSnapshot());snapshot_set = true;}…/* Done with the snapshot used for parsing/planning */if (snapshot_set)PopActiveSnapshot();…// 在PortalStart中调用GetTransactionSnapshot(),为executor的执行做准备PortalStart(portal, NULL, 0, InvalidSnapshot, NULL);…// 在PortalRun中通过CdbDispatchXXX dispatch这个snaphost(一般是activesnapshot)到QE上(void) PortalRun(portal, ...);…}QE进程的执行入口是exec_mpp_query(),它直接使用QD dispatch过来的快照(DtxContextInfo结构体)中:PostgresMain(){…case 'M': /* MPP dispatched stmt from QD */…// 获取QD生成并dispatch过来的(分布式)快照serializedDtxContextInfo = pq_getmsgbytes(&input_message,serializedDtxContextInfolen);…// 已经存储在QEDtxContextInfo全局变量中,可以在exec_mpp_query中使用exec_mpp_query();…}

分布式快照
typedef struct SnapshotData{… (xmin, xmax, xip ...)/** GP: Global information about which transactions are visible for a* distributed transaction, with cached local xids*/DistributedSnapshotWithLocalMapping distribSnapshotWithLocalMapping; // 结构见下}typedef struct DistributedSnapshotWithLocalMapping{DistributedSnapshot ds; /* DistributedSnapshot结构简略如下:{DistributedSnapshotId distribSnapshotId;DistributedTransactionId xmin;DistributedTransactionId xmax;int32 count;/* Array of distributed transactions in progress. */DistributedTransactionId *inProgressXidArray;} */…int32 currentLocalXidsCount;int32 maxLocalXidsCount;TransactionId *inProgressMappedLocalXids;} DistributedSnapshotWithLocalMapping;
distribSnapshotId表示分布式事务ID(Dtxid) xmin,xmax和SnapshotData中的作用一致,只不过作用于分布式事务ID上 inProgressXidArray对应SnapshotData中的xip,表示运行中的分布式事务ID列表

总结

参考资料
Greenplum:基于 PostgreSQL 的分布式数据库内核揭秘 (下篇) The Internals of PostgreSQL : Chapter 5 Concurrency Control (interdb.jp):
https://www.interdb.jp/pg/pgsql05.htmlMVCC in PostgreSQL-4. Snapshots / Habr: https://habr.com/en/company/postgrespro/blog/479512/ 《PostgreSQL技术内幕 事务》作者:张树杰 《数据库事务处理的艺术》作者:李海翔

来一波 “在看”、“分享”和 “赞” 吧!文章转载自Greenplum中文社区,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




