postgresql源码学习(44)—— PostmasterMain(1) —— 内存初始化与信号处理函数设置

一、 Postmaster与Postgres进程的关系

      pg使用的是多进程架构,众多进程之中,最为重要的就是在前一节main函数中出现的Postmaster与Postgres进程。

  • 守护进程Postmaster:负责PG的启动和关闭;监听和接收客户端连接请求,为其派生服务进程Postgres
  • 服务进程Postgres:接收并执行客户端发送的命令,完成客户端的各种数据库操作并返回执行结果

     在Linux中,Postmaster仅是Postgres进程的一个符号链接;在windows中,Postmaster是Postgres的一个拷贝。因此,pg中的所有核心功能,几乎都是Postgres进程完成的。

     从main函数的调用中也可以看到,单用户模式下不需要Postmaster进程,只需要它的本体Postgres进程即可。

二、 守护进程Postmaster执行流程

1. 主要作用

Postmaster文件夹下包括下列文件:

      由此很明显能看出Postmaster进程的主要用途 —— 派生子进程。这既包括前面提到的Postgres进程,也包括大量的后台进程。

       它还负责中断、数据库启停等操作的处理,Postmaster进程本身并不直接处理这些事件,而是指派子进程在适当的事件处理。同时,它要在数据库崩溃时重启系统。

       Postmaster及其子进程通过共享内存和信号库(在启动时初始化)进行通信,这种多进程设计使其稳定性更强,即使某个后台进程崩溃也不会影响系统中其他进程的工作,Postmaster只需要重置共享内存即可从单个后台进程的崩溃中恢复(只是原理上是这样,实际上通过os命令kill pg的用户进程,都有可能整个pg实例崩溃)。

2. 代码核心流程

       这部分源码位于postmaster.c文件,由于内容太长,我们先只看初始化内存及信号处理设置的部分。

三、 PostmasterMain(1) —— 内存初始化与切换

       在main函数中,调用MemoryContextInit函数首先创建了顶层上下文TopMemoryContext和错误恢复处理的上下文ErrorContext。

/*
 * MemoryContextInit
 *      Start up the memory-context subsystem.
 *
 * This must be called before creating contexts or allocating memory in
 * contexts.  TopMemoryContext and ErrorContext are initialized here;
 * other contexts must be created afterwards.
 */
void
MemoryContextInit(void)
{
    AssertState(TopMemoryContext == NULL);

    /*
     * First, initialize TopMemoryContext, which is the parent of all others.
     */
    TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
                                             "TopMemoryContext",
                                             ALLOCSET_DEFAULT_SIZES);

    /*
     * Not having any other place to point CurrentMemoryContext, make it point to TopMemoryContext.  Caller should change this soon!
     */
    CurrentMemoryContext = TopMemoryContext;

    /*
     * Initialize ErrorContext
     */
    ErrorContext = AllocSetContextCreate(TopMemoryContext,
                                         "ErrorContext",
                                         8 * 1024,
                                         8 * 1024,
                                         8 * 1024);
    MemoryContextAllowInCriticalSection(ErrorContext, true);
}

        PostmasterMain中,调用AllocSetContextCreate()函数创建用于Postmaster工作的内存上下文PostmasterContext,并调用函数MemoryContextSwitchTo()将当前上下文切换到此处。这样若是在Postmaster模块若是出现内存相关的问题,不会影响到其余模块。

/*
 * Postmaster main entry point
 */
void
PostmasterMain(int argc, char *argv[])
{
    int         opt;
    int         status;
    char       *userDoption = NULL;
    bool        listen_addr_saved = false;
    int         i;
    char       *output_config_variable = NULL;

    InitProcessGlobals();

    PostmasterPid = MyProcPid;

    IsPostmasterEnvironment = true;

    /*
     * 在checkDataDir()函数执行前不创建任何文件,但先用umask命令用来设置限制新建文件权限的掩码
     */
    umask(PG_MODE_MASK_OWNER);

    /*
     * 初始化内存上下文。TopMemoryContext是所有内存上下文的根,直到pg退出才会释放,后面会为各类操作单独创建内存上下文,避免内存泄漏问题。
     */
    PostmasterContext = AllocSetContextCreate(TopMemoryContext,
                                              "Postmaster",
                                              ALLOCSET_DEFAULT_SIZES);
    MemoryContextSwitchTo(PostmasterContext);

四、 PostmasterMain(2) —— 信号处理函数设置

1. 原理简介

       信号是os响应某些状况而产生的事件,它可以明确由一个进程发给另一个进程,用这种方法传递信息或协调操作。进程可以自定义信号处理函数来处理信号,pg就是充分利用了这一点。

进程有权响应或屏蔽信号(SIGKILL和SIGSTOP不能屏蔽):

  • BlockSig:要屏蔽的信号集
  • UnBlockSig:不希望屏蔽的信号集
  • AutoBlockSig:在进行用户连接认证时需要屏蔽的信号集

        在设置响应信号的处理函数之前,要先通过PG_SETMASK函数把这些信号全部屏蔽,然后通过pgsignal函数为感兴趣的信号设置处理函数。

2. 常见信号处理函数及信号功能

① 处理函数SIGHUP_handler:处理SIGHUP信号。当配置文件发生改变时会产生SIGHUP信号,重读postgresql.conf文件,然后向子进程发送相同的信号,并重新装载pg_hba.conf和pg_ident.conf

② 处理函数pmdie:处理SIGTERM,SIGINT,SIGQUIT三种信号,这就是刚学关闭pg时的三种模式

  • SIGTERM:smart shutdown(类似oracle shutdown normal)
  • SIGINT:fast shutdown(类似oracle shutdown immediate)
  • SIGQUIT:immediate shutdown(类似oracle shutdown abort)

③ 处理函数reaper:当系统中有子进程退出时,子进程会给postmaster进程发送一个SIGCHLD信号,主进程收到后调用reaper函数清理退出的子进程(不同的进程有各自处理方式)。

其他主要信号量如下:

3. 相关源码

/* Initialize paths to installation files,获取安装路径 */
    getInstallationPaths(argv[0]);

    /*
     * Set up signal handlers for the postmaster process. 信号处理函数设置
     */

/* 在设置响应信号的处理函数之前,要先通过PG_SETMASK函数把这些信号全部屏蔽,然后通过pgsignal函数为感兴趣的信号设置处理函数 */

    pqinitmask();
    PG_SETMASK(&BlockSig);   
    pqsignal_pm(SIGHUP, SIGHUP_handler);    /* reread config file and have children do same */
    pqsignal_pm(SIGINT, pmdie); /* send SIGTERM and shut down */
    pqsignal_pm(SIGQUIT, pmdie);    /* send SIGQUIT and die */
    pqsignal_pm(SIGTERM, pmdie);    /* wait for children and shut down */
    pqsignal_pm(SIGALRM, SIG_IGN);  /* ignored */
    pqsignal_pm(SIGPIPE, SIG_IGN);  /* ignored */
    pqsignal_pm(SIGUSR1, sigusr1_handler);  /* message from child process */
    pqsignal_pm(SIGUSR2, dummy_handler);    /* unused, reserve for children */
    pqsignal_pm(SIGCHLD, reaper);   /* handle child termination */

#ifdef SIGURG
    pqsignal_pm(SIGURG, SIG_IGN);   /* ignored */
#endif

#ifdef SIGTTIN
    pqsignal_pm(SIGTTIN, SIG_IGN);  /* ignored */
#endif
#ifdef SIGTTOU
    pqsignal_pm(SIGTTOU, SIG_IGN);  /* ignored */
#endif

    /* ignore SIGXFSZ, so that ulimit violations work like disk full */
#ifdef SIGXFSZ
    pqsignal_pm(SIGXFSZ, SIG_IGN);  /* ignored */
#endif

后面是读取并设置GUC参数的部分,下节继续学习。

参考

《PostgreSQL数据库内核分析》第二章

http://www.javashuo.com/article/p-mmvwlzmf-ka.html

PG内存上下文管理(MemoryContext)——内存上下文树 - 肥叔菌 - 博客园

PG内存上下文管理(MemoryContext)——AllocSetContext:抽象类MemoryContext的实现 - 肥叔菌 - 博客园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hehuyi_In

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值