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();
......
}