PostgreSQL启动过程中的那些事七:初始化共享内存和信号:四 shmem中初始化subtrans

pg初始化shmem,给其加上索引"ShmemIndex"后,接着就在shmem里初始化xlog。然后依次初始化clog、subtrans、twophase、multixact。安排按clog、subtrans、multixact、twophase的顺序写,把twophase放到multixact之后是因为前面三个用了相同的算法和数据结构,连起来写可以加深印象和归类记忆,本来想把初始化clog、subtrans、multixact放到一篇文章里写,因为篇幅太长还是分开了,看的时候这几篇文章可以结合起来看。

pg子事务管理器(pg_subtrans manager)是一个类提交事务管理器(pg_clog-like manager,关于clog见《pg启动过程中的那些事七-三》。),为每一个事务存储父事务ID。它是实现嵌套事务的一个基础部分。主事务有一个无效的父事务ID,且每个子事务以其为父事务。这颗事务树能方便的从子事务找到父事务,但不能从父事务找到子事务。子事务只需要为当前打开的事务记住子事务信息。这样没有必要像CLOG那样为进程崩溃或重启数据库保存数据。

因为不保存因崩溃恢复需要的数据,所以没有和XLOG的交互。在pg数据库启动期间,只要把子事务的当前活跃页置0就可以了。

上面概述了子事务,下来我们看方法调用流程

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


PostgreSQL启动过程中的那些事七:初始化共享内存和信号:四 shmem中初始化subtrans_第1张图片

初始化SUBTRANS方法调用流程图

2初始化xlog相关结构

话说main()->…->PostmasterMain()->…->reset_shared()-> CreateSharedMemoryAndSemaphores()->…-> CLOGShmemInit(),初始化子事务相关数据结构ClogCtlData等,用作内存里管理和缓存子事务日志文件(存放在"data/pg_subtrans"文件夹里的文件)。

SUBTRANSShmemInit()调用ShmemInitStruct(),在其中调用hash_search()在哈希表索引"ShmemIndex"中查找"SUBTRANSCtl",如果没有,就在shmemIndex中给" SUBTRANS Ctl "分一个HashElement和ShmemIndexEnt(entry),在其中的Entry中写上"SUBTRANS Ctl"。返回ShmemInitStruct(),再调用ShmemAlloc()在共享内存上给"SUBTRANS Ctl"相关结构(见下面“subtrans相关结构图”)分配空间,设置entry(在这儿及ShmemIndexEnt类型变量)的成员location指向该空间,size成员记录该空间大小,最后返回SUBTRANSShmemInit(),让SlruCtlData *类型全局变量SubTransCtl指向SlruCtlData 类型静态全局变量SubTransCtlData,SubTransCtlData的起始地址就是在shmem里给" SUBTRANS Ctl"相关结构分配的内存起始地址,设置其中SubTransCtlData结构类型的成员值。相关变量、结构定义和初始化完成后数据结构图在下面。

#define SubTransCtl(&SubTransCtlData)

static SlruCtlData SubTransCtlData;

typedef struct SlruCtlData

{

SlruShared shared;

/*

* This flag tells whether to fsync writes(true for pg_clog, false for

* pg_subtrans).

*/

bool do_fsync;

/*

* Decide which of two page numbers is"older" for truncation purposes. We

* need to use comparison of TransactionIdshere in order to do the right

* thing with wraparound XID arithmetic.

*/

bool (*PagePrecedes)(int, int);

/*

* Dir is set during SimpleLruInit and does notchange thereafter. Since

* it's always the same, it doesn't need to bein shared memory.

*/

char Dir[64];

} SlruCtlData;

typedef SlruCtlData *SlruCtl;

/*

* Shared-memorystate

*/

typedef struct SlruSharedData

{

LWLockId ControlLock;

/* Number of buffers managed by this SLRU structure */

int num_slots;

/*

* Arrays holding info for each buffer slot. Page number is undefined

* when status is EMPTY, as is page_lru_count.

*/

char **page_buffer;

SlruPageStatus*page_status;

bool *page_dirty;

int *page_number;

int *page_lru_count;

LWLockId *buffer_locks;

/*

* Optional array of WAL flush LSNs associatedwith entries in the SLRU

* pages.If not zero/NULL, we must flush WAL before writing pages (true

* for pg_clog, false for multixact,pg_subtrans, pg_notify). group_lsn[]

* has lsn_groups_per_page entries per bufferslot, each containing the

* highest LSN known for a contiguous group ofSLRU entries on that slot's

* page.

*/

XLogRecPtr *group_lsn;

int lsn_groups_per_page;

/*----------

* We mark a page "most recentlyused" by setting

* page_lru_count[slotno]= ++cur_lru_count;

* The oldest page is therefore the one withthe highest value of

* cur_lru_count- page_lru_count[slotno]

* The counts will eventually wrap around, butthis calculation still

* works as long as no page's age exceedsINT_MAX counts.

*----------

*/

int cur_lru_count;

/*

* latest_page_number is the page number of thecurrent end of the log;

* this is not critical data, since we use itonly to avoid swapping out

* the latest page.

*/

int latest_page_number;

} SlruSharedData;

typedef SlruSharedData *SlruShared;

下面看看初始化完" SUBTRANS Ctl"相关结构后在内存中的结构图


PostgreSQL启动过程中的那些事七:初始化共享内存和信号:四 shmem中初始化subtrans_第2张图片

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

为了精简上图,把创建shmem的哈希表索引"ShmemIndex"时创建的HCTL结构删掉了,这个结构的作用是记录创建可扩展哈希表的相关信息。增加了左边灰色底的部分,描述共享内存/shmem里各变量物理布局概览,由下往上,由低地址到高地址。其中的"SUBTRANSCtl"即clog的相关结构图下面分别给出,要不上面的图太大太复杂了。

PostgreSQL启动过程中的那些事七:初始化共享内存和信号:四 shmem中初始化subtrans_第3张图片

SUBTRANS相关结构图


你可能感兴趣的:(PostgreSQL)