Greenplum保证数据隔离的“秘密武器”:快照
本文中涉及到的代码版本是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 adistributed 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 : Chapt er 5 Concurrency Control (interdb.jp):
https://www.interdb.jp/pg/pgsql05.html -
MVCC in PostgreSQL-4. Snapshots / Habr: https://habr.com/en/company/postgrespro/blog/479512/
-
《PostgreSQL技术内幕 事务》作者:张树杰 -
《数据库事务处理的艺术》作者:李海翔
来一波 “在看”、“分享” 和 “赞” 吧!
本文分享自微信公众号 - Greenplum中文社区(GreenplumCommunity)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。