zoukankan      html  css  js  c++  java
  • PostgreSQL启动main函数都干了什么(一)

    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 '01', allowInCritSection = 0 '00', methods = 0xd1bbe0 <AllocSetMethods>, parent = 0x0, firstchild = 0x0, nextchild = 0x0,
     name = 0x14f9c70 "TopMemoryContext", reset_cbs = 0x0}, blocks = 0x0, freelist = {0x0 <repeats 11 times>}, initBlockSize = 8192, maxBlockSize = 8192, nextBlockSize = 8192, allocChunkLimit = 1024, keeper = 0x0}

    可以到初始化的数据块为8K,最大8K,allocChunkLimit为1024.

    这样就把这个"TopMemoryContext"初始化完成了,然后把该内存上下文赋值给CurrentMemoryContext。

    (gdb) p CurrentMemoryContext
    $58 = (MemoryContext) 0x14f9bb0
    (gdb) p    TopMemoryContext 
    $59 = (MemoryContext) 0x14f9bb0
    (gdb) 

    现在初始化"TopMemoryContext"的第一个孩子,"ErrorContext"。

    处理方式跟上面的区别,就是parent是"TopMemoryContext",并且内存上下文是通过MemoryContext->methods->AllocSetAlloc这个函数指针来分配内存的

    这个后面要单独分析。

    (gdb) p    *ErrorContext
    $65 = {type = T_AllocSetContext, isReset = 1 '01', allowInCritSection = 0 '00', methods = 0xd1bbe0 <AllocSetMethods>, parent = 0x14f9bb0, firstchild = 0x0, nextchild = 0x0, nam
    e = 0x14f9d80 "ErrorContext", reset_cbs = 0x0}
    (gdb) p    *ErrorContext->parent 
    $66 = {type = T_AllocSetContext, isReset = 0 '00', allowInCritSection = 0 '00', methods = 0xd1bbe0 <AllocSetMethods>, parent = 0x0, firstchild = 0x14f9cc0, nextchild = 0x0, nam
    e = 0x14f9c70 "TopMemoryContext", reset_cbs = 0x0}
    (gdb) p *ErrorContext->parent->firstchild
    $67 = {type = T_AllocSetContext, isReset = 1 '01', allowInCritSection = 0 '00', methods = 0xd1bbe0 <AllocSetMethods>, parent = 0x14f9bb0, firstchild = 0x0, nextchild = 0x0, nam
    e = 0x14f9d80 "ErrorContext", reset_cbs = 0x0}
    (gdb) 

    这样就把ErrorContext初始化完成了。PG中所有的内存上下文都挂载"TopMemoryContext"下面。

    后面就是大量的环境变量设置了,以及root校验。

    最后调用函数"PostmasterMain(argc,argv)"。这就是我们的大管家,后面再写这部分。

  • 相关阅读:
    ECharts之柱状图 饼状图 折线图
    Vue自定义指令(directive)
    HDU 1231 最大连续子序列
    POJ 2533 Longest Ordered Subsequence
    HDU 1163 Eddy's digital Roots
    HDU 2317 Nasty Hacks
    HDU 2571 命运
    HDU 4224 Enumeration?
    HDU 1257 最少拦截系统
    HDU 2740 Root of the Problem
  • 原文地址:https://www.cnblogs.com/sangli/p/5833141.html
Copyright © 2011-2022 走看看