PostgreSQL启动过程中的那些事七:初始化共享内存和信号八:shme
这一节pg初始化锁管理器,通过InitLocks例程实现,主要是创建了三个哈希表。第一个哈希表"LOCKhash"用于管理锁,第二个哈希表"PROCLOCKhash"用于管理进程锁,第三个"LOCALLOCKhash"用于管理本地锁信息。其中第一个和第二个哈希表都是共享哈希表,第三个是非关系哈希表。初始化第三个哈希表"LOCALLOCK hash"时在共享内存哈希表索引"ShmemIndex"里没有创建索引,因为这个哈希表不在共享内存里,而是在MemoryContext "LOCALLOCK hash" 里分配的内存。 pg中的锁有三种类型:自旋锁(spinlock)、轻量锁(LWLock)、常规锁(Lock),作为一个主题另行讨论。 1先上个图,看一下函数调用过程梗概,中间略过部分细节
初始化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和ShmemIndexEnt(entry),在其中的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和ShmemIndexEnt(entry),在其中的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 struct LOCKTAG { 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 struct LOCK { /* 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 struct PROCLOCKTAG { /* 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 struct PROCLOCK { /* 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 struct LOCALLOCKTAG { LOCKTAG lock; /* identifies the lockable object */ LOCKMODE mode; /* lock mode for this table entry */ } LOCALLOCKTAG;
typedef struct LOCALLOCKOWNER { /* * 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. */ struct ResourceOwnerData *owner; int64 nLocks; /* # of times held by this owner */ } LOCALLOCKOWNER;
typedef struct LOCALLOCK { /* 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)
初始化完LOCK相关结构的内存结构图 为了精简上图,把创建shmem的哈希表索引"ShmemIndex"时创建的HCTL结构删掉了,这个结构的作用是记录创建可扩展哈希表的相关信息。增加了左边灰色底的部分,描述共享内存/shmem里各变量物理布局概览,由下往上,由低地址到高地址。图中黄色的索引项就是本节新增加的索引项。其中的"LOCK hash"相关结构内存图、"PROCLOCK hash"相关结构内存图下面分别给出,要不上面的图太大太复杂了。在MemoryContext "PROCLOCK hash"中分配的哈希表"PROCLOCK hash"相关结构内存图和当前pg中的MemoryContext相关实例图也在下边一并给出。
"LOCK hash"相关结构图
"PROCLOCK hash"相关结构图
"LOCALLOCKhash"相关结构图
当前pg中的MemoryContext结构图 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- SQLite CURRENT_TIMESTAMP始终是1970-01-01
- Oracle查询性能优化(面试题:数据库查询优化也是常问的问题
- ruby-on-rails – 如何在集成测试中检查正在进行的AJAX调用
- How I explained OOD to my wife[Thinking in OOD]
- Vue cli构建及项目打包以及出现的问题解决
- (grep)正则表达式匹配非ASCII字符?
- C# 如何在PDF中绘制不同风格类型的文本
- Oracle数据库12cR2(项目实战之一):在Windows上安装Oracl
- 使用自动布局可视化格式与Swift?
- SAPUI5内置的AJAX类库对POST请求的处理不提交HTTP HEADERS