1. 程式人生 > >Postgresql - 原始碼 - 資料庫啟動

Postgresql - 原始碼 - 資料庫啟動

資料庫啟動,一個很簡單的舉動,只需要執行一條命令,

OS上執行的service postgresql start 或者 systemctl status postgresql.service

或是直接執行資料庫啟動命令

/usr/local/pgsql/bin/pg_ctl start -D ${PGDATA} -s -w -t 300 -l /usr/local/pgsql/logs/pgstartup.log

 

下面我們從原始碼中來看看資料庫啟動中到底做了什麼操作。

 

1. 無論我們執行以上三種啟動方式,最後都要歸結到

/usr/local/pgsql/bin/pg_ctl start -D ${PGDATA} -s -w -t 300 -l /usr/local/pgsql/logs/pgstartup.log

那我們接下來就要從pg_ctl來入手。

在src/bin/pg_ctl/pg_ctl.c的main函式中,有一段程式碼是解析我們執行的哪個命令。

先從int main(){ ...... } 開始入手。

 

/* 先解析引數,判斷引數,判斷引數中是否有help 或 version */

if (argc > 1){ ...... }

 

/* 判斷action引數,D e l m N o */

while (optind < argc)

    {

......

}

 

/* 判斷啟動引數,每一個執行的引數都是需要做什麼 */

while (optind < argc)

    {

        while ((c = getopt_long(argc, argv, "cD:e:l:m:N:o:p:P:sS:t:U:wW",

                                long_options, &option_index)) != -1)

        {

            switch (c)

            {......

/* 判斷引數是否為執行啟動 */

else if (strcmp(argv[optind], "start") == 0)

ctl_command = START_COMMAND;

......

}

 

/* 定義資料夾等配置資訊 */

......

pg_config = getenv("PGDATA");

adjust_data_dir();

......

switch (ctl_command)

    { ......

        case START_COMMAND:

            do_start();

            break;

......

}

 

2.src/bin/pg_ctl/pg_ctl.c的 do_start函式。

static void

do_start(void)

{

......

/* 判斷是否存在啟動的程序,如果有程序,報錯。*/

    if (ctl_command != RESTART_COMMAND)

    {

        old_pid = get_pgpid(false);

        if (old_pid != 0)

            write_stderr(_("%s: another server might be running; "

                         "trying to start server anyway\n"),

                         progname);

    }

/* 讀取配置 pgdata/postmaster.opts檔案 */

    read_post_opts();

/* 判斷是否有-D引數,表示資料檔案的資料夾 */

    /* No -D or -D already added during server start */

    if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL)

        pgdata_opt = "";

    if (exec_path == NULL)

        exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);

    if (exec_path == NULL)

        exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);

    /*

     * If possible, tell the postmaster our parent shell's PID (see the

     * comments in CreateLockFile() for motivation). Windows hasn't got

     * getppid() unfortunately.

     */

......

 

    pm_pid = start_postmaster();

 

/* 判斷是否需要等待 */

    if (do_wait)

    {

        print_msg(_("waiting for server to start..."));

        switch (wait_for_postmaster(pm_pid, false))

        {

            case POSTMASTER_READY:

                print_msg(_(" done\n"));

                print_msg(_("server started\n"));

                break;

            case POSTMASTER_STILL_STARTING:

                print_msg(_(" stopped waiting\n"));

                write_stderr(_("%s: server did not start in time\n"),

                             progname);

                exit(1);

                break;

            case POSTMASTER_FAILED:

                print_msg(_(" stopped waiting\n"));

                write_stderr(_("%s: could not start server\n"

                             "Examine the log output.\n"),

                             progname);

                exit(1);

                break;

        }

    }

    else

/* 等待啟動完成 */

        print_msg(_("server starting\n"));

......

}

 

3. do_start中的 start_postmaster函式

原始碼中對start_postmaster函式的註釋資訊

/*

* Start the postmaster and return its PID.

*

* Currently, on Windows what we return is the PID of the shell process

* that launched the postmaster (and, we trust, is waiting for it to exit).

* So the PID is usable for "is the postmaster still running" checks,

* but cannot be compared directly to postmaster.pid.

*

* On Windows, we also save aside a handle to the shell process in

* "postmasterProcess", which the caller should close when done with it.

*/

start_postmaster(void)

{

......

# 啟動子程序

pm_pid = fork();

......

}