PostgreSQL启动过程中的那些事一:初始化TopMemoryContext和ErrorContext
1先上个示意图,看一下函数调用过程梗概,中间略过部分细节
前面标1的是初始化TopMemoryContext
前面标2的是初始化ErrorContext
初始化TopMemoryContext和ErrorContext的方法调用过程图
2初始化TopMemoryContext的过程
话说main()->…->PostmasterMain()->…->MemoryContextInit()->AllocSetContextCreate()(以后用“->”表示调用),AllocSetContextCreate()函数主要是初始化AllocSet类型的变量,AllocSet的类型是“AllocSetContext*”,AllocSetContext是结构,定义见下面,也就是说,AllocSetContextCreate()函数主要是初始化AllocSetContext类型的变量。
在MemoryContextInit()函数中,一上来就是下面这句,调用AllocSetContextCreate初始化TopMemoryContext。
TopMemoryContext =AllocSetContextCreate((MemoryContext) NULL,
"TopMemoryContext",0,8 * 1024, 8 * 1024);
TopMemoryContext是个全局变量,定义如下
MemoryContext TopMemoryContext = NULL;
从MemoryContextInit()函数调用过来初始化Memorycontext类型的全局变量TopMemoryContext,不是AllocSetContextCreate()函数主要是初始化AllocSetContext类型的变量吗,怎么又初始化上Memorycontext类型的全局变量TopMemoryContext了呢,先卖个关子,容后再说。这是PostgresSQL(以后简称pg)一个比较秒的地方,也涉及了后面用到的面向过程编程的一个技巧。
TopMemoryContext这个全局变量在pg有至关重要,统领全局的地位,以后自然明白。
AllocSetContext定义如下:
typedef struct AllocSetContext
{
MemoryContextData header; /* Standardmemory-context fields */
/* Info aboutstorage allocated in this context: */
AllocBlock blocks; /* head of list of blocks in this set */
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
bool isReset; /* T = no space allocedsince last reset */
/* Allocationparameters for this context: */
Size initBlockSize; /* initial blocksize */
Size maxBlockSize; /* maximum blocksize */
Size nextBlockSize; /* next block sizeto allocate */
AllocBlock keeper; /* if not NULL, keep this block over resets */
}AllocSetContext;
AllocSetContext中有三个变量的类型分别是MemoryContextData、AllocBlock、AllocChunk,这些类型是pg管理AllocSet和MemoryContext涉及内存机制的主要元素,搭起pg管理AllocSet和MemoryContext涉及的内存的架构,后面会逐个提到。
在AllocSetContextCreate()函数中,刚声明一个AllocSet类型的变量conext,马上就调用MemoryContextCreate()函数,代码见下。MemoryContextCreate()函数从名字就能看出来是创建MemoryContext的,创建一个MemoryContext类型的值后返回,返回后做了类型强制转换为AllocSet赋给context。调用MemoryContextCreate()函数创建MemoryContext时传的第二个参数是要创建类型的大小,这里取的就是AllocSetContext的大小,而不是MemoryContext的大小。
AllocSet context;
context = (AllocSet) MemoryContextCreate(T_AllocSetContext,
sizeof(AllocSetContext), &AllocSetMethods,parent, name);
MemoryContextCreate()函数主要是初始化MemoryContext,MemoryContext的类型是“MemoryContextData *”,MemoryContextData是个结构,定义见下面。
typedef struct MemoryContextData
{
NodeTag type; /* identifies exact kind of context */
MemoryContextMethods *methods; /*virtual function table */
MemoryContext parent; /* NULL ifno parent (toplevel context) */
MemoryContext firstchild; /* head of linkedlist of children */
MemoryContext nextchild; /* next childof same parent */
char *name; /* context name (just for debugging) */
}MemoryContextData;
MemoryContextCreate()函数的简化代码如下,主要是声明一个MemoryContext类型的局部变量node,分配内存并初始化。注意,这时还没有初始化TopMemoryContext,所以node的内存空间是malloc出来的。MemoryContext类型的局部变量node初始化完后返回。
MemoryContext
MemoryContextCreate(NodeTag tag, Size size,
MemoryContextMethods*methods,
MemoryContextparent,
const char *name)
{
MemoryContext node;
Size needed = size + strlen(name) + 1;
if(TopMemoryContext == NULL)
{
/*Special case for startup: use good ol' malloc */
&nbs