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 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 '\001', allowInCritSection = 0 '\000', 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",
,
* ,
* );

在初始化"TopMemoryContext"的时候,默认以及设定了最小块为0,初始化为8*1024,最大为8*1024

(gdb) p    *set
$ = {header = {type = T_AllocSetContext, isReset = '\001', allowInCritSection = '\000', methods = 0xd1bbe0 <AllocSetMethods>, parent = 0x0, firstchild = 0x0, nextchild = 0x0,
name = 0x14f9c70 "TopMemoryContext", reset_cbs = 0x0}, blocks = 0x0, freelist = {0x0 <repeats times>}, initBlockSize = , maxBlockSize = , nextBlockSize = , allocChunkLimit = , keeper = 0x0}

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

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

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

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

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

这个后面要单独分析。

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

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

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

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

PostgreSQL启动main函数都干了什么(一)的更多相关文章

  1. swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?

    date: 2018-8-01 14:22:17title: swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?description: 阅读 sowft 框架源码, 了解 sowf ...

  2. loadView在App启动时到底都干了些什么?

    loadView在App启动时到底都干了些什么? 查阅苹果官方文档如下: 1. 当你访问一个ViewController的view属性时,如果此时view的值是nil,那么,ViewControlle ...

  3. iOS应用启动main函数

    #import <UIKit/UIKit.h> #import "AppDelegate.h" int main(int argc, char * argv[]) { ...

  4. C++ main()函数及其参数

    1.首先,想想C/C++在main函数之前和之后会做些什么? 我们看看底层的汇编代码: __start: : init stack; init heap; open stdin; open stdou ...

  5. WPF点滴(1) Main 函数

    应用程序的入口函数是main函数,在Console程序和Winform程序main函数都有清晰的定义,可以很容易找到,但是WPF的工程文件中却找不到main函数的定义,是WPF不需要main函数吗?N ...

  6. C语言中main函数的参数

    转自:http://blog.csdn.net/cnctloveyu/article/details/3905720 我们经常用的main函数都是不带参数的.因此main 后的括号都是空括号.实际上, ...

  7. C++向main函数传递参数的方法(实例已上传至github)

    通常情况下,我们定义的main函数都只有空形参列表: int main(){...} 然而,有时我们确实需要给mian传递实参,一种常见的情况是用户设置一组选项来确定函数所要执行的操作.例如,假定ma ...

  8. Linux C编程--main函数参数解析

    我们经常用的main函数都是不带参数的.因此main 后的括号都是空括号.实际上,main函数可以带参数,这个参数可以认为是 main函数的形式参数.C语言规定main函数的参数只能有两个, 习惯上这 ...

  9. c/c++中main函数参数讲解

    参考地址: http://blog.csdn.net/cnctloveyu/article/details/3905720 我们经常用的main函数都是不带参数的.因此main 后的括号都是空括号.实 ...

随机推荐

  1. Java项目打包方式分析

    [TOC] 概述 在项目实践过程中,有个需求需要做一个引擎能执行指定jar包的指定main方法. 起初我们以一个简单的spring-boot项目进行测试,使用spring-boot-maven-plu ...

  2. 在vue2.0中使用sass

    第一步:使用sass必须安装下面三个东西 cnpm install node-sass --save //安装node-sass cnpm install sass-loader --save //安 ...

  3. Spring AOP分析(1) -- 基本概念

    AOP全称是Aspect Oriented Programming,面向切面编程,是面向对象编程(OOP:Object Oriented Programming)的补充和完善.一般在系统中,OOP利用 ...

  4. font-size:100% 原因

    The browser default which is something like 16pt for Firefox, You can check by going into Firefox op ...

  5. Spring框架学习之注解配置与AOP思想

         上篇我们介绍了Spring中有关高级依赖关系配置的内容,也可以调用任意方法的返回值作为属性注入的值,它解决了Spring配置文件的动态性不足的缺点.而本篇,我们将介绍Spring的又一大核心 ...

  6. Windows系统下python3中安装pyMysql

    python2和python3是不兼容的,在py2中,链接数据库使用的是mysqldb,但在py3中是不能用的. 解决办法就是在py3中数据库使用的模块是pyMysql. 在dos窗口中安装第三方库会 ...

  7. Oracle-1 - :超级适合初学者的入门级笔记,CRUD,事务,约束 ......

    Oracle 更改时间: 2017-10-25  -  21:33:49 2017-10-26  -  11:43:19 2017-10-27  -  19:06:57 2017-10-28  -  ...

  8. oracle 归档模式开启后数据库宕机解决过程

    首先按照网友说的shutdown immediately,结果hang了半个小时也么反应. 然后检查日志,全盘搜索.trc,发现 (D:\app\oracle\diag\rdbms\cms1u\cms ...

  9. 配置好postfix邮件服务器之后就可以使用它来发送邮件了

    下面是一段摘自W3school关于php mail函数的栗子,经过测试发现两个问题. <?php $to = "somebody@example.com, somebodyelse@e ...

  10. JavaScript系列----面向对象的JavaScript(2)

    本文中心: 这篇文章比较难懂,所以读起来比较晦涩.所以,我简单列一下提纲: 在第一部分,从函数原型开始谈起,目的是想搞明白,这个属性是什么,为什么存在,在创建对象的的时候起到了什么作用! 在第二部分, ...