• PostgreSQL 各个后台进程关系的理解


    启动PostgreSQL 进程后,可以看到:

    [root@localhost ~]# ps -ef | grep post
    root 2991 2925 0 10:42 pts/1 00:00:00 su - postgres
    postgres 2992 2991 0 10:42 pts/1 00:00:00 -bash
    postgres 3029 2992 0 10:42 pts/1 00:00:00 /usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data
    postgres 3031 3029 0 10:42 ? 00:00:00 postgres: checkpointer process
    postgres 3032 3029 0 10:42 ? 00:00:00 postgres: writer process
    postgres 3033 3029 0 10:42 ? 00:00:00 postgres: wal writer process
    postgres 3034 3029 0 10:42 ? 00:00:00 postgres: autovacuum launcher process
    postgres 3035 3029 0 10:42 ? 00:00:00 postgres: stats collector process
    root 3061 3039 0 10:43 pts/2 00:00:00 grep post
    [root@localhost ~]#

    不难发现,

    checkpointer process,

    writer process,

    wal writer process

    autovacuum launcher process

    stats collector process 

    都是 postgres 进程的子进程。

    那么是如何做到的呢?各个子进程名称不同,而且还被同一个父进程来生成,用来完成不同的工作。

    有点 龙生九子各不同的感觉。

    看代码(Postmaster.c):

    #define StartupDataBase()        StartChildProcess(StartupProcess)                    
    #define StartBackgroundWriter()         StartChildProcess(BgWriterProcess)                    
    #define StartCheckpointer()        StartChildProcess(CheckpointerProcess)                    
    #define StartWalWriter()        StartChildProcess(WalWriterProcess)                    
    #define StartWalReceiver()        StartChildProcess(WalReceiverProcess)                    
                                
                                
                                
                                
    "/*
     * Main idle loop of postmaster
     */
    "                            
    static int                            
    ServerLoop(void)                            
    {                            
    …                            
        for (;;)                        
        {                        
            ……                    
                                
            /*                    
             * If no background writer process is running, and we are not in a                    
             * state that prevents it, start one.  It doesn't matter if this                    
             * fails, we'll just try again later.  Likewise for the checkpointer.                    
             */                    
            if (pmState == PM_RUN || pmState == PM_RECOVERY ||                    
                pmState == PM_HOT_STANDBY)                
            {                    
                if (CheckpointerPID == 0)                
                    CheckpointerPID = StartCheckpointer();            
                if (BgWriterPID == 0)                
                    BgWriterPID = StartBackgroundWriter();            
            }                    
                                
            …                    
        }                        
    …                            
    }                            
                                
                                
     * StartChildProcess -- start an auxiliary process for the postmaster                            
     *                            
     * xlop determines what kind of child will be started.    All child types                        
     * initially go to AuxiliaryProcessMain, which will handle common setup.                            
     *                            
     * Return value of StartChildProcess is subprocess' PID, or 0 if failed                            
     * to start subprocess.                            
     */                            
    static pid_t                            
    StartChildProcess(AuxProcType type)                            
    {                            
        pid_t    pid;                    
        char    *av[10];                    
        int    ac = 0;                    
        char    typebuf[32];                    
                                
        /*                        
         * Set up command-line arguments for subprocess                        
         */                        
        av[ac++] = "postgres";                        
                                
        #ifdef EXEC_BACKEND                        
            av[ac++] = "--forkboot";                    
            av[ac++] = NULL;            /* filled in by postmaster_forkexec */        
        #endif                        
                                
        snprintf(typebuf, sizeof(typebuf), "-x%d", type);                        
        av[ac++] = typebuf;                        
                                
        av[ac] = NULL;                        
        Assert(ac < lengthof(av));                        
                                
        #ifdef EXEC_BACKEND                        
            pid = postmaster_forkexec(ac, av);                    
                                
        #else    /* !EXEC_BACKEND */                    
                                
            pid = fork_process();                    
                                
            if (pid == 0)        /* child */            
            {                    
                IsUnderPostmaster = true;                /* we are a postmaster subprocess now */
                                
                /* Close the postmaster's sockets */                
                ClosePostmasterPorts(false);                
                                
                /* Lose the postmaster's on-exit routines and port connections */                
                on_exit_reset();                
                                
                /* Release postmaster's working memory context */                
                MemoryContextSwitchTo(TopMemoryContext);                
                MemoryContextDelete(PostmasterContext);                
                PostmasterContext = NULL;                
                                
                AuxiliaryProcessMain(ac, av);                
                ExitPostmaster(0);                
            }                    
        #endif   /* EXEC_BACKEND */                        
                                
        if (pid < 0)                        
        {                        
            /* in parent, fork failed */                    
            int            save_errno = errno;        
                                
            errno = save_errno;                    
            switch (type)                    
            {                    
                case StartupProcess:                
                    ereport(LOG,            
                            (errmsg("could not fork startup process: %m")));    
                    break;            
                case BgWriterProcess:                
                    ereport(LOG,            
                       (errmsg("could not fork background writer process: %m")));            
                    break;            
                case CheckpointerProcess:                
                    ereport(LOG,            
                            (errmsg("could not fork checkpointer process: %m")));    
                    break;            
                case WalWriterProcess:                
                    ereport(LOG,            
                            (errmsg("could not fork WAL writer process: %m")));    
                    break;            
                case WalReceiverProcess:                
                    ereport(LOG,            
                            (errmsg("could not fork WAL receiver process: %m")));    
                    break;            
                default:                
                    ereport(LOG,            
                            (errmsg("could not fork process: %m")));    
                    break;            
            }                    
                                
            /*                    
             * fork failure is fatal during startup, but there's no need to choke                    
             * immediately if starting other child types fails.                    
             */                    
            if (type == StartupProcess)                    
                ExitPostmaster(1);                
            return 0;                    
        }                        
                                
        /*                        
         * in parent, successful fork                        
         */                        
        return pid;                        
    }                            

    可以看到 ,Postmaster.c 的 主循环中,安排了如下部分:

    if (BgWriterPID == 0)                
                    BgWriterPID = StartBackgroundWriter();   

    而根据宏定义, StartBackgroundWriter() 就是 StartChildProcess(BgWriterProcess)
    在 通用程序 StartChildProcess 中,根据参数的不同,来完成对不同的程序的 fork动作:

    av[ac++] = "postgres"; 
    snprintf(typebuf, sizeof(typebuf), "-x%d", type);
    两句,就是我们ps 的时候能够看到  postgres: writer process 信息的原因。

    AuxiliaryProcessMain(ac, av); 是各个子进程真正各自为战的入口点。
    而关于 EXEC_BACKEND ,可以看如下这段(I put the following just for memo):

    http://postgresql.1045698.n5.nabble.com/where-EXEC-BACKEND-td2008305.html


    > hi, 

    > actually i try to execute postgres step by step (on paper) 
    > i don't retreive where EXEC_BACKEND is initialized 
    > can any one help me? 
    > it is very important for me 

    Nowhere.  If you want it, you have to define it manually in 
    pg_config_manual.h. 

    EXEC_BACKEND is a source code hack that allows the Unix build (which 
    normally uses only fork() without exec()) to follow the same startup 
    code as the Windows version (which uses CreateProcess(), equivalent to 
    both fork() and exec()), allowing for better debuggability for those of 
    us that do not use Windows. 

    If you want to follow postmaster initialization on a POSIX platform, 
    it's easier if you just assume that EXEC_BACKEND is not defined. 

     
  • 相关阅读:
    LintCode-174.删除链表中倒数第n个节点
    LintCode-165.合并两个排序链表
    LintCode-371.用递归打印数字
    LintCode-140.快速幂
    LintCode-373.奇偶分割数组
    NOI 2015 品酒大会 (后缀数组+并查集)
    NOI 2016 优秀的拆分 (后缀数组+差分)
    POJ 2774 Long Long Message (后缀数组+二分)
    BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)
    POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)
  • 原文地址:https://www.cnblogs.com/gaojian/p/2736805.html
Copyright © 2020-2023  润新知