数据库启动,一个很简单的举动,只需要执行一条命令,
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();
......
}