话说查询“selectcname,comp from test1,test2 where test1.id=test2.id;”发送到服务器端,走查询分支exec_simple_query,先调用start_xact_command初始化了事务管理相关对象和资源,接着调用pg_parse_query,通过Lex和Yacc对传入sql语句进行词法语法解析,生成解析树。下来调用GetTransactionSnapshot方法做内存快照。内存快照和事务隔离级别紧密相关,其中可重复读和序列化隔离级别每个数据库事务使用一个快照,读未提交和读已提交隔离级别每个语句使用一个快照。序列化隔离级别除快照外还使用predicate锁。
1
下面是做内存快照的调用序列图。
Postgres服务进程简查之开始事务调用序列图
上图红色方框中显示了获取内存快照的方法调用过程,在GetSnapshotData方法中根据事务隔离级别等情况获取相应快照,一般可优化语句(增、删、查、改)都需要快照,然后注册相应快照。下面是获取快照方法GetTransactionSnapshot的流程图。
GetTransactionSnapshot方法流程图
GetTransactionSnapshot()方法根据事务隔离级别 分别处理取快照的情况。如果事务隔离级别是读未提交、读已提交,调用GetSnapshotData(&CurrentSnapshotData)方法获取一个快照赋给CurrentSnapshot,返回CurrentSnapshot。如果事务隔离级别是可重复读或序列化,且是事务里第一次获取快照,直接返回CurrentSnapshot;不是第一次且是可重复读 事务隔离级别,调用GetSnapshotData(&CurrentSnapshotData) 方法获取一个快照赋给CurrentSnapshot,然后调用RegisterSnapshotOnOwner(CurrentSnapshot,TopTransactionResourceOwner)方法在资源管理器TopTransactionResourceOwner里注册这个快照;不是第一次且是序列化 事务隔离级别,调用RegisterSerializableTransaction(&CurrentSnapshotData)方法,根据需要调用GetSnapshotData方法获取快照并调用RegisterSnapshotOnOwner方法在资源属主TopTransactionResourceOwner上注册快照,并初始化一个可序列化事务SERIALIZABLEXACT结构和哈西表。最后,不管什么情况都返回当前快照,调用PushActiveSnapshot方法,把这个快照推入由ActiveSnapshotElt构成的“活跃快照”栈。
在pg里快照就是数据结构SnapshotData,定义如下,表示某个时刻内存里对象的状态,下面是快照SnapshotData结构定义:
typedefstruct SnapshotData
{
SnapshotSatisfiesFuncsatisfies; /* tuple test function */
/*
* The remaining fields areused only for MVCC snapshots,and are normally
* just zeroes in specialsnapshots. (But xmin and xmaxare used
* specially byHeapTupleSatisfiesDirty.)
*
* An MVCC snapshot cannever see the effects of XIDs >= xmax. It can see
* the effects of all older XIDs except thoselisted in the snapshot.
xmin
* is stored as anoptimization to avoid needing to search the XID arrays
* for most tuples.
*/
TransactionIdxmin; /* all XID < xmin are visible to me */
TransactionIdxmax; /* all XID >= xmax are invisible to me */
uint32 xcnt; /* # of xact ids in xip[] */
TransactionId *xip; /* array of xact IDs in progress */
/* note: all ids in xip[]satisfy xmin <= xip[i] < xmax */
int32 subxcnt; /* # of xact ids in subxip[] */
TransactionId *subxip; /* array of subxact IDs in progress */
bool suboverflowed; /* has the subxip array overflowed?*/
bool takenDuringRecovery; /*recovery-shaped snapshot? */
/*
* note: all ids in subxip[]are >= xmin,but we don't bother filtering
* out any that are >= xmax
*/
CommandId curcid; /* in my xact,CID < curcid are visible*/
uint32 active_count; /* refcount on ActiveSnapshot stack*/
uint32 regd_count; /* refcount onRegisteredSnapshotList */
bool copied; /* false if it's a static snapshot */
} SnapshotData;
这里面最复杂的是在序列化隔离级别下事务的正常运转,部分体现在RegisterSerializableTransaction方法调用了RegisterSerializableTransactionInt方法,其流程图在下面
RegisterSerializableTransactionInt流程图
RegisterSerializableTransactionInt里,利用predicatelock相关的哈西表,PredXactListData、PredXactListElementData等组成的链表结构,RWConflictPoolHeaderData、RWConflictData等组成的链表结构等一起管理predicate lock和serializablexact结构,(具体个数据结构参见《Postgresql启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁》)利用可序列化快照隔离(Serializable SnapshotIsolation (SSI)),实现了事务的完全可序列化隔离级别,以支持该事务隔离级别下事务的正常运转。
利用可序列化快照隔离(Serializable Snapshot Isolation (SSI))的相关情况最初是在下面的论文里描述:
Michael J. Cahill,Uwe R枚hm,and Alan D. Fekete. 2008.
Serializableisolation for snapshot databases.
InSIGMOD '08: Proceedings of the 2008 ACM SIGMOD
internationalconference on Management of data,
pages729-738,New York,NY,USA. ACM.
http://doi.acm.org/10.1145/1376616.1376690
在下面的博士论文里做了进一步阐述。
Michael James Cahill. 2009.
Serializable Isolation for Snapshot Databases.
Sydney Digital Theses.
University of Sydney,School of Information Technologies.
http://hdl.handle.net/2123/5353
就到这儿吧。
------------ 转载请注明出处,来自博客: blog.csdn.net/beiigang beigang.iteye.com