DB Version:9.5.3
环境:CentOS7.x
调试工具:GDB
source:src/backend/main/main.c
56 /*
57 * Any Postgres server process begins execution here.
58 */
59 int
60 main(int argc, char *argv[])
61 {
62 bool do_check_root = true;
63 sleep(30);
64 progname = get_progname(argv[0]);
修改一下代码,睡它30s。或者执行postgres可执行文件,set args 也OK。
启动数据库:
/usr/local/psql-9.5.3/bin/pg_ctl -D db2/ -l logfile start -m fast
查看后台进程PID:
[postgres@localhost ~]$ ps -ef |grep postgres
root 57843 57805 0 10:58 pts/1 00:00:00 su - postgres
postgres 57844 57843 0 10:58 pts/1 00:00:00 -bash
postgres 57977 1 0 11:01 pts/1 00:00:00 /usr/local/psql-9.5.3/bin/postgres -D db2
postgres 57981 57844 0 11:02 pts/1 00:00:00 ps -ef
postgres 57982 57844 0 11:02 pts/1 00:00:00 grep --color=auto postgres
进入调试模式,需要等30s:
cgdb -p 57977 (gdb) b main.c:64 Breakpoint 1 at 0x676229: file main.c, line 64. (gdb) c Continuing. Breakpoint 1, main (argc=3, argv=0x7ffceddcbe88) at main.c:64 (gdb)
首先pg进入main函数,最先是获取到progname:
(gdb) p argv[0] $1 = 0x7ffceddcd6d6 "/usr/local/psql-9.5.3/bin/postgres"
其实这个里面还是根据main函数的第一个参数进行字符串拆分计算出progname
具体可以跟一下函数"get_progname":
(gdb) p progname $15 = 0x14f9010 "postgres"
初始化内存(MemoryContextInit):
这个是数据库启动的时候初始化的第一块内存,我们一起来看看里面的内容。
在看这个之前,我们先来了解一下PG几个关于内存的结构体
typedef struct MemoryContextData *MemoryContext;
typedef struct MemoryContextData { NodeTag type; /* identifies exact kind of context */ /* these two fields are placed here to minimize alignment wastage: */ bool isReset; /* T = no space alloced since last reset */ bool allowInCritSection; /* allow palloc in critical section */ MemoryContextMethods *methods; /* virtual function table */ MemoryContext parent; /* NULL if no parent (toplevel context) */ MemoryContext firstchild; /* head of linked list of children */ MemoryContext nextchild; /* next child of same parent */ char *name; /* context name (just for debugging) */ MemoryContextCallback *reset_cbs; /* list of reset/delete callbacks */ } MemoryContextData;
我们先看看MemoryContextData是如何被初始化的:
函数 MemoryContextCreate MemSet(node, 0, size); node->type = tag; node->methods = methods; node->parent = NULL; /* for the moment */ node->firstchild = NULL; node->nextchild = NULL; node->isReset = true; node->name = ((char *) node) + size; strcpy(node->name, name); (gdb) p *node $31 = {type = T_AllocSetContext, isReset = 1 ' 01', allowInCritSection = 0 ' 00', methods = 0xd1bbe0 <AllocSetMethods>, parent = 0x0, firstchild = 0x0, nextchild = 0x0, name = 0x 14f9c70 "TopMemoryContext", reset_cbs = 0x0}
其实这里最重要的是methods这个参数,这是个函数指针,还有里面其实最主要的就是内存上下文的父子关系
我们回头再细研究这个东东。
函数返回的是MemoryContext转成AllocSet.就是下面的结构体,其实MemoryContextData成了它的header。
这就是后面的NODE那个大enum,直接小转大。
typedef struct AllocSetContext { MemoryContextData header; /* Standard memory-context fields */ /* Info about storage allocated in this context: */ AllocBlock blocks; /* head of list of blocks in this set */ AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */ /* Allocation parameters for this context: */ Size initBlockSize; /* initial block size */ Size maxBlockSize; /* maximum block size */ Size nextBlockSize; /* next block size to allocate */ Size allocChunkLimit; /* effective chunk size limit */ AllocBlock keeper; /* if not NULL, keep this block over resets */ } AllocSetContext; typedef AllocSetContext *AllocSet;
我们来看看这个set内容,里面包含了数据库初始化的数据块大小,最大块,下一个块以及chunk的limit.
TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL, "TopMemoryContext", 0, 8 * 1024, 8 * 1024);
在初始化"TopMemoryContext"的时候,默认以及设定了最小块为0,初始化为8*1024,最大为8*1024
(gdb) p *set $45 = {header = {type = T_AllocSetContext, isReset = 1 '