PostgreSQL V9.6 谓词锁--02

时间:2023-02-05 05:56:32

支持SSI技术的可序列化的事务的表示

    在事务的隔离级别为SERIALIZABLE时,PostgreSQL为支持SSI技术,使用“SERIALIZABLEXACT”表示可序列化的事务,并标识事务与读写冲突之间的关系。

typedef struct SERIALIZABLEXACT  // SERIALIZABLEXACT是一个可序列化的事务

{

    VirtualTransactionId vxid;    /* The executing process always has one of these. */  //虚拟的事务ID

    /*

     * We use two numbers to track the order that transactions commit. Before

     * commit, a transaction is marked as prepared, and prepareSeqNo is set.

     * Shortly after commit, it's marked as committed, and commitSeqNo is set.

     * This doesn't give a strict commit order, but these two values together

     * are good enough for us, as we can always err on the safe side and

     * assume that there's a conflict, if we can't be sure of the exact

     * ordering of two commits.

     *

     * Note that a transaction is marked as prepared for a short period during

     * commit processing, even if two-phase commit is not used. But with

     * two-phase commit, a transaction can stay in prepared state for some

     * time.

     */

    //以下两个变量,用以表明事务的提交顺序

    SerCommitSeqNo prepareSeqNo; //PreCommit_CheckForSerializationFailure()函数赋值

    SerCommitSeqNo commitSeqNo;  //ReleasePredicateLocks()函数赋值

 

    /* these values are not both interesting at the same time */

    union

    {

        SerCommitSeqNo earliestOutConflictCommit;       /* when committed with conflict out */

        SerCommitSeqNo lastCommitBeforeSnapshot;        /* when not committed or  no conflict out */

    }SeqNo;

    // outConflictsinConflicts用以表示事务间的相互影响, inConflicts是本事务影响了其他事务, outConflicts是其他事务影响了本事务

    SHM_QUEUE    outConflicts;    /* 数据不能被读的“写事务的列表”,即想要读的数据因被别的事务写过则本事务不能读取  */

    SHM_QUEUE    inConflicts;    /* 不能看到本事务写的数据的“读事务的列表”,即本事务写过的数据不能被其他事务看到  */

    SHM_QUEUE    predicateLocks; //事务上的谓词锁列表

    SHM_QUEUE    finishedLink;   /* list link in FinishedSerializableTransactions */  //FinishedSerializableTransactions”是session中全局共享的事务列表,表示已经完成的可序列化的事务,即已经提交的事务。特别注意,已经完成的事务,依旧可能会和正在执行的事务构成读写冲突(这是快照隔离技术的缺陷,因此才诞生了可序列化的快照隔离、即SSI技术)

 

    /*

     * for r/o transactions: list of concurrent r/w transactions that we could

     * potentially have conflicts with, and vice versa for r/w transactions

     */

    SHM_QUEUE    possibleUnsafeConflicts;  //对于只读事务而言,存在可能的不安全的冲突(读写事务带来的不安全的冲突)

 

    TransactionId topXid;        /* top level xid for the transaction, if one exists; else invalid */

    TransactionId finishedBefore;  //本事务之前已经完成的事务ID

    TransactionId xmin;            /* the transaction's snapshot xmin */

    uint32        flags;           /* OR'd combination of values defined below */

    int            pid;            //进程的ID

} SERIALIZABLEXACT;

读写冲突

    PostgreSQL使用“RWConflictData”表示事务之间的读写冲突关系,这样的关系是两个事务之间的一条“边”,如果有多个事务,则事务之间的读写冲突就有出边和入边,所以表示出边关系的outLinksxactOut都是指向另外一个事务的,表示入边关系的inLinksxactIn都是其他事务指向本事务的一个读写冲突。

    一个读写冲突,是指t1事务要读t2事务写的数据,这样导致t1outLink指向t2t2inLink指向t1。如果写操作先发生(t2事务发生在前,通过MVCC机制,发生读同一个数据的事务t2的读操作能够被检测出来,即不允许发生 ?? 试验)

typedef struct RWConflictData   //事务之间,表示:“读写”冲突。是两个事务之间因“读写冲突”建立起的联系

{

    SHM_QUEUE    outLink;        //自一个“sxact”发出的冲突链接

    SHM_QUEUE    inLink;         //指向一个“sxact”的冲突链接

    SERIALIZABLEXACT *sxactOut; // SERIALIZABLEXACT是一个可序列化的事务,sxactOut表示本事务引发的一个冲突,指向了其他事务

    SERIALIZABLEXACT *sxactIn;  // SERIALIZABLEXACT是一个可序列化的事务,sxactIn表示指向本事务的冲突

}RWConflictData;

    PostgreSQL中,所有的读写冲突最后汇聚在“RWConflictPool”读写冲突池中。

typedef struct RWConflictData *RWConflict;

 

typedef struct RWConflictPoolHeaderData

{

    SHM_QUEUE    availableList;

    RWConflict   element;

}RWConflictPoolHeaderData;  -----------------------

                                                 

typedef struct RWConflictPoolHeaderData    *RWConflictPoolHeader;

 

static RWConflictPoolHeader    RWConflictPool;  //读写冲突池,一个session中全局共享

而读写冲突池的操作关系如图X-XX所示,从图中可以看出:

q  获取逻辑元组的时候(如调用heapgettup()函数),通过CheckForSerializableConflictOut()函数来检测和设置读写冲突

q  在隔离级别为序列化、通过GetTransactionSnapshot()函数获取事务的快照的时候,调用SetPossibleUnsafeConflict()函数设置事务间读写冲突的关系

PostgreSQL V9.6 谓词锁--02