设为首页 收藏本站
查看: 897|回复: 0

[经验分享] PostgreSQL启动过程中的那些事七:初始化共享内存和信号八:shmem中初始化常规锁管理器

[复制链接]

尚未签到

发表于 2016-11-21 08:14:23 | 显示全部楼层 |阅读模式
       这一节pg初始化锁管理器,通过InitLocks例程实现,主要是创建了三个哈希表。第一个哈希表"LOCKhash"用于管理锁,第二个哈希表"PROCLOCKhash"用于管理进程锁,第三个"LOCALLOCKhash"用于管理本地锁信息。其中第一个和第二个哈希表都是共享哈希表,第三个是非关系哈希表。初始化第三个哈希表"LOCALLOCK hash"时在共享内存哈希表索引"ShmemIndex"里没有创建索引,因为这个哈希表不在共享内存里,而是在MemoryContext "LOCALLOCK hash"里分配的内存。
pg中的锁有三种类型:自旋锁(spinlock)、轻量锁(LWLock)、常规锁(Lock),作为一个主题另行讨论。
 
1先上个图,看一下函数调用过程梗概,中间略过部分细节
 

DSC0000.bmp

初始化Lockmgr方法调用流程图

  
 
  
2初始化xlog相关结构
  
话说main()->…->PostmasterMain()->…->reset_shared() ->CreateSharedMemoryAndSemaphores()>…->InitLocks(),在shmem里分配了三个哈希表。第一个哈希表"LOCK hash"用于管理锁,第二个哈希表"PROCLOCK hash"用于管理进程锁,第三个"LOCALLOCK hash"用于管理本地锁信息。其中第一个和第二个哈希表都是共享哈希表,第三个是非关系哈希表。初始化第三个哈希表"LOCALLOCK hash"时在共享内存哈希表索引"ShmemIndex"里没有创建索引,因为这个哈希表不在共享内存里,而是在MemoryContext "LOCALLOCK hash"里分配的内存。
  
InitLocks()->ShmemInitHash()->ShmemInitStruct(),在其中调用hash_search()在哈希表索引"ShmemIndex"中查找"LOCK hash",如果没有,就在shmemIndex中给"LOCK hash"分一个HashElement和ShmemIndexEntentry),在其中的Entry中写上"LOCKhash"。返回ShmemInitStruct(),再调用ShmemAlloc()在共享内存上给"LOCKhash"相关结构(见下面"LOCK hash"相关结构图)分配空间,设置entry(在这儿即ShmemIndexEnt类型变量)的成员location指向该空间,size成员记录该空间大小,然后返回ShmemInitHash(),调用hash_create(),创建哈希表"LOCK hash",最后返回ShmemInitHash(),让HTAB *类型静态全局变量LockMethodLockHash指向哈希表"LOCK hash"
  
接着InitLocks()->ShmemInitHash()->ShmemInitStruct(),在其中调用hash_search()在哈希表索引"ShmemIndex"中查找"PROCLOCK hash",如果没有,就在shmemIndex中给"PROCLOCK hash"分一个HashElement和ShmemIndexEntentry),在其中的Entry中写上"PROCLOCKhash"。返回ShmemInitStruct(),再调用ShmemAlloc()在共享内存上给"PROCLOCKhash"相关结构(见下面"PROCLOCK hash"相关结构图)分配空间,设置entry(在这儿即ShmemIndexEnt类型变量)的成员location指向该空间,size成员记录该空间大小,然后返回ShmemInitHash(),调用hash_create(),创建哈希表"PROCLOCK hash",最后返回ShmemInitHash(),让HTAB *类型静态全局变量LockMethodProcLockHash指向哈希表"PROCLOCK hash"
  
接着InitLocks()->hash_create(),在其中调用AllocSetContextCreate(),创建MemoryContext "LOCALLOCK hash"(做个回顾,当前MemoryContext见下面的当前MemoryContext结构图),调用DynaHashAlloc(),在MemoryContext "LOCALLOCK hash"上分配空间,创建哈希表索引"LOCALLOCKhash"(见下面"LOCALLOCK hash"相关结构图),最后返回InitLocks(),让HTAB *类型静态全局变量LockMethodLocalHash指向哈希表"LOCALLOCK hash"
  
相关变量、结构定义和初始化完成后数据结构图在下面。
  
LOCKTAG结构被定义用于填充16字节。请注意,如果pg要扩大OID,BlockNumber,或TransactionId超过32位,这将需要调整。

  
       LOCKTAG包含lockmethodid是为了共享内存里一个哈希表能够存储不同lockmemthods的锁。

  
typedef structLOCKTAG

  
{

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

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

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

  
    uint16      locktag_field4; /*a 16-bit ID field */

  
    uint8       locktag_type;   /* see enum LockTagType */

  
    uint8       locktag_lockmethodid;   /* lockmethodindicator */

  
} LOCKTAG;

  
 

  
每个被锁对象的锁信息:

  
tag:可锁对象的唯一标识符

  
grantMask:目前授予该对象的所有类型锁的位掩码

  
/*

  
 *Per-locked-object lock information:

  
 *

  
 * tag -- uniquelyidentifies the object being locked

  
 * grantMask --bitmask for all lock types currently granted on this object.

  
 * waitMask --bitmask for all lock types currently awaited on this object.

  
 * procLocks --list of PROCLOCK objects for this lock.

  
 * waitProcs --queue of processes waiting for this lock.

  
 * requested --count of each lock type currently requested on the lock

  
 *      (includes requests already granted!!).

  
 * nRequested --total requested locks of all types.

  
 * granted -- countof each lock type currently granted on the lock.

  
 * nGranted --total granted locks of all types.

  
 *

  
 * Note: thesecounts count 1 for each backend. Internally to a backend,

  
 * there may bemultiple grabs on a particular lock, but this is not reflected

  
 * into sharedmemory.

  
 */

  
typedef structLOCK

  
{

  
    /* hash key */

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

  
 

  
    /* data */

  
    LOCKMASK    grantMask;      /* bitmask for lock types already granted */

  
    LOCKMASK    waitMask;       /* bitmask for lock types awaited */

  
    SHM_QUEUE   procLocks;      /* list of PROCLOCK objects assoc. with lock */

  
    PROC_QUEUE  waitProcs;      /* list of PGPROC objects waiting on lock */

  
    int         requested[MAX_LOCKMODES];       /* counts ofrequested locks */

  
    int         nRequested;     /* total ofrequested[] array */

  
    int         granted[MAX_LOCKMODES];/* counts of granted locks */

  
    int         nGranted;       /* total ofgranted[] array */

  
} LOCK;

  
 

  
pg可以有多个不同的backend进程在同一个开锁对象上持有或等待锁。pg需要为每个持有者/等待着存储一些信息。这些保存在结构PROCLOCK里。

  
PROCLOCKTAG是在proclock哈希表里查找一个PROCLOCK项的关键信息。一个PROCLOCKTAG值唯一的标识一个可锁对象和一个持有者/等待着的组合。(这儿pg能使用指针,因为PROCLOCKTAG仅需要在PROCLOCK的生命周期里唯一,且不会在lock和proc生存期以为)

  
为了不同的目的,backend进程可以持有同一个锁:独立于会话锁,backend进程跟踪事务锁。但是,这个在共享内存状态中没有反映出来:pg仅跟踪持有锁的backend进程。这是可以的,因为backend进程不能阻塞自己。

  
holdMask字段显示已经授予的由proclock代表的锁。注意,可能有一个具有0 holdMask的proclock对象,对于任何锁,进程当前正在等待它。负责,holdMask是0的proclock对象在方便的时候被尽快回收。

  
 

  
* releaseMask is workspace for LockReleaseAll(): it showsthe locks due

  
 * to be releasedduring the current call.  This must onlybe examined or

  
 * set by thebackend owning the PROCLOCK.

  
每一个PROCLOCK对象被链接到链表,为了相关LOCK对象和所属PGPROC对象。注意,PROCLOCK对象一被创建就就加入到这些链表,甚至还没有锁lock被授予的时候。等待lock锁被授予的PGPROC进程也会被链接到锁的等待进程(waitProcs)队列。

  
 

  
typedef structPROCLOCKTAG

  
{

  
    /* NB: we assume this struct contains no padding! */

  
    LOCK      *myLock;         /* link to per-lockable-object information */

  
    PGPROC    *myProc;         /* link to PGPROC of owning backend */

  
} PROCLOCKTAG;

  
 

  
typedef structPROCLOCK

  
{

  
    /* tag */

  
    PROCLOCKTAG tag;            /* uniqueidentifier of proclock object */

  
 

  
    /* data */

  
    LOCKMASK    holdMask;       /* bitmask for lock types currently held */

  
    LOCKMASK    releaseMask;    /* bitmask for lock types to be released */

  
    SHM_QUEUE   lockLink;       /* list link in LOCK's list of proclocks */

  
    SHM_QUEUE   procLink;       /* list link in PGPROC's list of proclocks */

  
} PROCLOCK;

  
 

  
每一个backend进程还维持一个本地哈希表,其记录着目前感兴趣的每一个锁lock的信息。特别的,本地表记录着获得的这些锁的时间。这允许不额外访问共享内存的情况下对同一个锁多请求被执行。为了pg能释放属于某个特别资源属主(ResourceOwner)的锁。pg还跟踪每个资源属主(ResourceOwner)获得的锁数

  
typedef structLOCALLOCKTAG

  
{

  
    LOCKTAG     lock;           /* identifies the lockable object */

  
    LOCKMODE    mode;           /* lock mode for this table entry */

  
} LOCALLOCKTAG;

  
 

  
typedef structLOCALLOCKOWNER

  
{

  
    /*

  
     * Note: if owner is NULL then the lock is heldon behalf of the session;

  
     * otherwise it is held on behalf of my currenttransaction.

  
     *

  
     * Must use a forward struct reference to avoidcircularity.

  
     */

  
    structResourceOwnerData *owner;

  
    int64nLocks;           /* # of times held by this owner */

  
} LOCALLOCKOWNER;

  
 

  
typedef structLOCALLOCK

  
{

  
    /* tag */

  
    LOCALLOCKTAG tag;           /* uniqueidentifier of locallock entry */

  
 

  
    /* data */

  
    LOCK      *lock;           /* associated LOCK object in shared mem */

  
    PROCLOCK   *proclock;       /* associated PROCLOCK object in shmem */

  
    uint32      hashcode;       /* copy of LOCKTAG's hash value */

  
    int64           nLocks;         /* totalnumber of times lock is held */

  
    int         numLockOwners;  /* # of relevantResourceOwners */

  
    int         maxLockOwners;  /* allocated size ofarray */

  
    LOCALLOCKOWNER*lockOwners; /* dynamically resizable array */

  
} LOCALLOCK;

  
 

  
#define LOCALLOCK_LOCKMETHOD(llock)((llock).tag.lock.locktag_lockmethodid)

  
 


DSC0001.bmp

 

初始化完LOCK相关结构的内存结构图

  
       为了精简上图,把创建shmem的哈希表索引"ShmemIndex"时创建的HCTL结构删掉了,这个结构的作用是记录创建可扩展哈希表的相关信息。增加了左边灰色底的部分,描述共享内存/shmem里各变量物理布局概览,由下往上,由低地址到高地址。图中黄色的索引项就是本节新增加的索引项。其中的"LOCK hash"相关结构内存图、"PROCLOCK hash"相关结构内存图下面分别给出,要不上面的图太大太复杂了。在MemoryContext "PROCLOCK hash"中分配的哈希表"PROCLOCK hash"相关结构内存图和当前pg中的MemoryContext相关实例图也在下边一并给出。

  

DSC0002.bmp
"LOCK hash"相关结构图

 

DSC0003.bmp
"PROCLOCK hash"相关结构图

 


DSC0004.bmp

"LOCALLOCKhash"相关结构图


DSC0005.bmp

当前pg中的MemoryContext结构图

 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-303153-1-1.html 上篇帖子: gridsql 资料 下篇帖子: PostgreSQL启动过程中的那些事七:初始化共享内存和信号十:shmem中初始化PROC索引、辅助进程和信号
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表