PostgreSQL启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁...

 

       这一节 pg 初始化 predicate 锁,支持可序列化事务隔离。通过 InitPredicateLocks 例程实现,主要是干了下面这么几件事:

A 创建了哈希表"PREDICATELOCKTARGET hash"

B 在上面的哈希表里增加了 ScratchTargetTag 结构的索引

C 创建了哈希表"PREDICATELOCK hash"

D 初始化了 "PredXactList" 相关结构

E 创建了哈希表"SERIALIZABLEXID hash"

F 初始化了RWConflictPool 相关结构

H 初始化了 "FinishedSerializableTransactions" 相关结构

I 初始化了 "OldSerXid SLRU Ctl" 相关结构

J 初始化了 "OldSerXidControlData" 相关结构

 

1 先上个图,看一下函数调用过程梗概,中间略过部分细节

 


PostgreSQL启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁...

初始化 PredicateLocks 方法调用流程图

 

2 初始化 PredicateLocks 相关结构

话说 main()-> ->PostmasterMain()-> ->reset_shared() -> CreateSharedMemoryAndSemaphores()> ->InitPredicateLocks() 做了下面相关结构的内存分配和初始化:

A 创建了哈希表"PREDICATELOCKTARGET hash"

B 在上面的哈希表里增加了 ScratchTargetTag 结构的索引

C 创建了哈希表"PREDICATELOCK hash"

D 初始化了 "PredXactList" 相关结构

E 创建了哈希表"SERIALIZABLEXID hash"

F 初始化了RWConflictPool 相关结构,用于处理读写冲突

H 初始化了 "FinishedSerializableTransactions" 相关结构

I 初始化了 "OldSerXid SLRU Ctl" 相关结构

J 初始化了 "OldSerXidControlData" 相关结构

初始化上面这些结构都会在共享内存 /shmem 哈希表索引 shmemIndex 中增加索引项,下面把初始化这些结构后的 shmemIndex 图放到下边,就不加一个索引一个图了,减小篇幅。不过这样就看不出先后顺序了,好在这些消失的信息对理解这些过程没什么影响。图中黄色的索引项就是本节新增加的索引项。


PostgreSQL启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁...

初始化完 PredicateLocks 相关结构 的共享内存结构图

       为了精简上图,把创建 shmem 的哈希表索引 "ShmemIndex" 时创建的 HCTL 结构删掉了,这个结构的作用是记录创建可扩展哈希表的相关信息,不过这个结构在 "ShmemIndex" 创建完成后也会由于出了对象作用域而消失。增加了左边灰色底的部分,描述 共享内存 /shmem 里各变量物理布局概览,由下往上,由低地址到高地址。 图中黄色的索引项就是本节新增加的索引项。

 

A 创建了哈希表"PREDICATELOCKTARGET hash"

InitPredicateLocks()->ShmemInitHash ()->ShmemInitStruct() 在其中 调用 hash_search() 在哈希表索引 "ShmemIndex" 中查找 "PREDICATELOCKTARGET hash" ,如果没有,就在 shmemIndex 中给 "PREDICATELOCKTARGET hash" 分一个 HashElement ShmemIndexEnt entry ,在其中的 Entry 中写上 "PREDICATELOCKTARGET hash" 。返回 ShmemInitStruct() ,再调用 ShmemAlloc() 在共享内存上给 "PREDICATELOCKTARGET hash" 相关结构(见下面 "PREDICATELOCKTARGET hash" 相关结构图 )分配空间,设置 entry (在这儿即ShmemIndexEnt 类型变量)的成员 location 指向该空间, size 成员记录该空间大小,然后返回 ShmemInitHash() ,调用 hash_create() ,创建哈希表 "PREDICATELOCKTARGET hash" ,最后返回 ShmemInitHash() ,让 HTAB * 类型静态 全局变量 PredicateLockTargetHash 指向 哈希表 "PREDICATELOCKTARGET hash"

相关结构定义见下面:

typedef struct PREDICATELOCKTARGETTAG

{

    uint32      locktag_field1 ; /* a 32-bit ID field */

    uint32      locktag_field2 ; /* a 32-bit ID field */

    uint32      locktag_field3 ; /* a 32-bit ID field */

    uint32      locktag_field4 ; /* a 32-bit ID field */

    uint32      locktag_field5 ; /* a 32-bit ID field */

} PREDICATELOCKTARGETTAG ;

typedef struct PREDICATELOCKTARGET

{

    /* hash key */

    PREDICATELOCKTARGETTAG tag ; /* unique identifier of lockable object */

 

    /* data */

    SHM_QUEUE   predicateLocks ; /* list of PREDICATELOCK objects assoc . with

                              * predicate lock target */

} PREDICATELOCKTARGET ;

 


PostgreSQL启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁...

"PREDICATELOCKTARGET hash" 相关结构图

 

B 在上面的哈希表里增加了 ScratchTargetTag 结构的索引

InitPredicateLocks() 调用 ShmemInitStruct() 在其中 调用 hash_search() 在哈希表索引 "PREDICATELOCKTARGET hash" 中查找 ScratchTargetTag (是 PREDICATELOCKTARGET 类型全局静态变量 ),如果没有,就把 ScratchTargetTag 作为哈希表 "PREDICATELOCKTARGET hash" (该哈希表索引的类型是 PREDICATELOCKTARGET )的第一个 索引项(参见 "PREDICATELOCKTARGET hash" 相关结构图 )。

C 创建了哈希表"PREDICATELOCK hash"

接着 InitPredicateLocks()->ShmemInitHash ()->ShmemInitStruct() 在其中 调用 hash_search() 在哈希表索引 "ShmemIndex" 中查找 "PREDICATELOCK hash" ,如果没有,就在 shmemIndex 中给 "PREDICATELOCK hash" 分一个 HashElement ShmemIndexEnt entry ,在其中的 Entry 中写上 "PREDICATELOCK hash" 。返回 ShmemInitStruct() ,再调用 ShmemAlloc() 在共享内存上给 "PREDICATELOCK hash" 相关结构(见下面 "PREDICATELOCK hash" 相关结构图 )分配空间,设置 entry (在这儿即ShmemIndexEnt 类型变量)的成员 location 指向该空间, size 成员记录该空间大小,然后返回 ShmemInitHash() ,调用 hash_create() ,创建哈希表 "PREDICATELOCK hash" ,最后返回 ShmemInitHash() ,让 HTAB * 类型静态 全局变量 PredicateLockHash 指向 哈希表 "PREDICATELOCK hash"

相关结构定义见下面:

typedef struct PREDICATELOCKTAG

{

    PREDICATELOCKTARGET * myTarget ;

    SERIALIZABLEXACT * myXact ;

} PREDICATELOCKTAG ;

typedef struct PREDICATELOCK

{

    /* hash key */

    PREDICATELOCKTAG tag ;       /* unique identifier of lock */

 

    /* data */

    SHM_QUEUE   targetLink ;       /* list link in PREDICATELOCKTARGET's list of

                              * predicate locks */

    SHM_QUEUE   xactLink ;     /* list link in SERIALIZABLEXACT's list of

                               * predicate locks */

    SerCommitSeqNo commitSeqNo ; /* only used for summarized predicate locks */

} PREDICATELOCK ;

 


PostgreSQL启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁...

"PREDICATELOCK hash" 相关结构图

 

D 初始化了 "PredXactList" 相关结构

InitPredicateLocks() 调用 ShmemInitStruct() 在其中 调用 hash_search() 在哈希表索引 "ShmemIndex" 中查找 "PredXactList " ,如果没有,就在 shmemIndex 中给 "PredXactList " 分一个 HashElement ShmemIndexEnt entry ,在其中的 Entry 中写上 "PredXactList " 。返回 ShmemInitStruct() ,再调用 ShmemAlloc() 在共享内存上给 "PredXactList " 相关结构(见下面“ PredXactList 相关结构图” )分配空间,设置 entry (在这儿及ShmemIndexEnt 类型变量)的成员 location 指向该空间, size 成员记录该空间大小 最后返回 InitPredicateLocks () ,让 PredXactList * 类型 全局变量 PredXact 指向 所分配内存 ,设置 PredXactList 结构类型的成员值。

相关结构定义见下面:

typedef struct PredXactListData

{

    SHM_QUEUE   availableList ;

    SHM_QUEUE   activeList ;

 

    /*

      * These global variables are maintained when registering and cleaning up

      * serializable transactions.  They must be global across all backends ,

      * but are not needed outside the predicate.c source file. Protected by

      * SerializableXactHashLock.

      */

    TransactionId SxactGlobalXmin ;     /* global xmin for active serializable

                                     * transactions */

    int         SxactGlobalXminCount ;    /* how many active serializable

                                     * transactions have this xmin */

    int         WritableSxactCount ;      /* how many non-read-only serializable

                                     * transactions are active */

    SerCommitSeqNo LastSxactCommitSeqNo ;      /* a strictly monotonically

                                            * increasing number for

                                            * commits of serializable

                                            * transactions */

    /* Protected by SerializableXactHashLock. */

    SerCommitSeqNo CanPartialClearThrough ;    /* can clear predicate locks

                                            * and inConflicts for

                                            * committed transactions

                                            * through this seq no */

    /* Protected by SerializableFinishedListLock. */

    SerCommitSeqNo HavePartialClearedThrough ; /* have cleared through this

                                            * seq no */

    SERIALIZABLEXACT * OldCommittedSxact ;      /* shared copy of dummy sxact */

 

    PredXactListElement element ;

}   PredXactListData ;

 

typedef struct PredXactListData * PredXactList ;

 

typedef struct SERIALIZABLEXACT

{

    VirtualTransactionId vxid ;  /* The executing process always has one of

                              * these. */

 

    /*

      * 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 ;

    SerCommitSeqNo commitSeqNo ;

 

    /* 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 ;

    SHM_QUEUE   outConflicts ; /* list of write transactions whose data we

                              * couldn't read. */

    SHM_QUEUE   inConflicts ;  /* list of read transactions which couldn't

                              * see our write. */

    SHM_QUEUE   predicateLocks ; /* list of associated PREDICATELOCK objects */

    SHM_QUEUE   finishedLink ; /* list link in

                              * FinishedSerializableTransactions */

 

    /*

      * 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 ;      /* invalid means still running; else

                                     * the struct expires when no

                                     * serializable xids are before this. */

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

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

    int         pid ;          /* pid of associated process */

} SERIALIZABLEXACT ;

 


PostgreSQL启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁...

PredXactList 相关结构图

 

E 创建了哈希表"SERIALIZABLEXID hash"

接着 InitPredicateLocks() 调用 ShmemInitHash ()->ShmemInitStruct() 在其中 调用 hash_search() 在哈希表索引 "ShmemIndex" 中查找 "SERIALIZABLEXID hash" ,如果没有,就在 shmemIndex 中给 "SERIALIZABLEXID hash" 分一个 HashElement ShmemIndexEnt entry ,在其中的 Entry 中写上 "SERIALIZABLEXID hash" 。返回 ShmemInitStruct() ,再调用 ShmemAlloc() 在共享内存上给 "SERIALIZABLEXID hash" 相关结构(见下面 "SERIALIZABLEXID hash" 相关结构图 )分配空间,设置 entry (在这儿即ShmemIndexEnt 类型变量)的成员 location 指向该空间, size 成员记录该空间大小,然后返回 ShmemInitHash() ,调用 hash_create() ,创建哈希表 "SERIALIZABLEXID hash" ,最后返回 ShmemInitHash() ,让 HTAB * 类型静态 全局变量 SerializableXidHash 指向 哈希表 "SERIALIZABLEXID hash"

相关结构定义见下面:

typedef struct SERIALIZABLEXIDTAG

{

    TransactionId xid ;

} SERIALIZABLEXIDTAG ;

typedef struct SERIALIZABLEXID

{

    /* hash key */

    SERIALIZABLEXIDTAG tag ;

 

    /* data */

    SERIALIZABLEXACT * myXact ;   /* pointer to the top level transaction data */

} SERIALIZABLEXID ;

 

 


PostgreSQL启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁...
 

"SERIALIZABLEXID hash" 相关结构图

 

F 初始化了RWConflictPool 相关结构,用于处理读写冲突

InitPredicateLocks() 调用 ShmemInitStruct() 在其中 调用 hash_search() 在哈希表索引 "ShmemIndex" 中查找 "RWConflictPool " ,如果没有,就在 shmemIndex 中给 "RWConflictPool " 分一个 HashElement ShmemIndexEnt entry ,在其中的 Entry 中写上 "RWConflictPool " 。返回 ShmemInitStruct() ,再调用 ShmemAlloc() 在共享内存上给 "RWConflictPool " 相关结构(见下面“ RWConflictPool FinishedSerializableTransactions 相关结构图相关结构图” )分配空间,设置 entry (在这儿及ShmemIndexEnt 类型变量)的成员 location 指向该空间, size 成员记录该空间大小 最后返回 InitPredicateLocks () ,让 RWConflictPoolHeaderData * 类型 全局变量 RWConflictPool 指向 所分内存 ,设置其中 RWConflictPoolHeaderData 结构类型的成员值。

相关结构定义见下面:

typedef struct RWConflictData

{

    SHM_QUEUE   outLink ;      /* link for list of conflicts out from a sxact */

    SHM_QUEUE   inLink ;           /* link for list of conflicts in to a sxact */

    SERIALIZABLEXACT * sxactOut ;

    SERIALIZABLEXACT * sxactIn ;

}   RWConflictData ;

typedef struct RWConflictPoolHeaderData

{

    SHM_QUEUE   availableList ;

    RWConflict element ;

}   RWConflictPoolHeaderData ;

 


PostgreSQL启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁...

RWConflictPool FinishedSerializableTransactions 相关结构图

 

H 初始化了 "FinishedSerializableTransactions" 相关结构

InitPredicateLocks() 调用 ShmemInitStruct() 在其中 调用 hash_search() 在哈希表索引 "ShmemIndex" 中查找 "FinishedSerializableTransactions " ,如果没有,就在 shmemIndex 中给 "FinishedSerializableTransactions " 分一个 HashElement ShmemIndexEnt entry ,在其中的 Entry 中写上 "FinishedSerializableTransactions " 。返回 ShmemInitStruct() ,再调用 ShmemAlloc() 在共享内存上给 "FinishedSerializableTransactions " 相关结构(见下面“ RWConflictPool FinishedSerializableTransactions 相关结构图相关结构图” )分配空间,设置 entry (在这儿及ShmemIndexEnt 类型变量)的成员 location 指向该空间, size 成员记录该空间大小 最后返回 InitPredicateLocks () ,让 SHM_QUEUE * 类型 全局变量 FinishedSerializableTransactions 指向 所分 内存,设置其中SubTransCtlData 结构类型的成员值。

 

I 初始化了 "OldSerXid SLRU Ctl" 相关结构

InitPredicateLocks()->OldSerXidInit()->SimpleLruInit()->ShmemInitStruct() 在其中 调用 hash_search() 在哈希表索引 "ShmemIndex" 中查找 "OldSerXid SLRU Ctl " ,如果没有,就在 shmemIndex 中给 "OldSerXid SLRU Ctl " 分一个 HashElement ShmemIndexEnt entry ,在其中的 Entry 中写上 "OldSerXid SLRU Ctl " 。返回 ShmemInitStruct() ,再调用 ShmemAlloc() 在共享内存上给 "OldSerXid SLRU Ctl " 相关结构(见下面“ OldSerXid SLRU Ctl OldSerXidControlData 相关结构图” )分配空间,设置 entry (在这儿及ShmemIndexEnt 类型变量)的成员 location 指向该空间, size 成员记录该空间大小 最后返回 SimpleLruInit () ,让 SlruCtlData * 类型 全局变量 OldSerXidSlruCtl 指向给 "OldSerXid SLRU Ctl " 相关结构分配的内存起始地址,设置其中 SlruCtlData 结构类型的成员值。

 

J 初始化了 "OldSerXidControlData" 相关结构

InitPredicateLocks()->OldSerXidInit() 调用 ShmemInitStruct() 在其中 调用 hash_search() 在哈希表索引 "ShmemIndex" 中查找 "OldSerXidControlData " ,如果没有,就在 shmemIndex 中给 "OldSerXidControlData " 分一个 HashElement ShmemIndexEnt entry ,在其中的 Entry 中写上 "OldSerXidControlData " 。返回 ShmemInitStruct() ,再调用 ShmemAlloc() 在共享内存上给 "OldSerXidControlData " 相关结构(见下面“ OldSerXid SLRU Ctl OldSerXidControlData 相关结构图” )分配空间,设置 entry (在这儿及ShmemIndexEnt 类型变量)的成员 location 指向该空间, size 成员记录该空间大小 最后返回 OldSerXidInit () ,让 OldSerXidControlData * 类型 全局变量 oldSerXidControl 指向给 "OldSerXidControlData " 相关结构分配的内存地址,设置其中 OldSerXidControlDat 结构类型的成员值。

相关结构定义见下面:

typedef struct OldSerXidControlData

{

    int         headPage ;     /* newest initialized page */

    TransactionId headXid ;      /* newest valid Xid in the SLRU */

    TransactionId tailXid ;      /* oldest xmin we might be interested in */

    bool        warningIssued ;    /* have we issued SLRU wrap-around warning? */

}   OldSerXidControlData ;

 


PostgreSQL启动过程中的那些事七:初始化共享内存和信号九:shmem中初始化Predicate锁...

OldSerXid SLRU Ctl OldSerXidControlData 相关结构图