后台一等公民进程StartupDataBase调用函数链,通过fork子进程AuxiliaryProcessMain来执行StartupProcessMain函数。

StartupDataBase() --> StartChildProcess(StartupProcess) --fork--> 子进程 AuxiliaryProcessMain --> StartupProcessMain函数
--> 父进程 return

StartChildProcess

StartChildProcess函数执行流程如下,子进程执行如下函数InitPostmasterChild、ClosePostmasterPorts、MemoryContextSwitchTo、MemoryContextDelete、AuxiliaryProcessMain,最后执行ExitPostmaster(0)。

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";
snprintf(typebuf, sizeof(typebuf), "-x%d", type);
av[ac++] = typebuf;
av[ac] = NULL;
Assert(ac < lengthof(av));
pid = fork_process();

if (pid == 0) { /* child */
InitPostmasterChild();
ClosePostmasterPorts(false); /* Close the postmaster's sockets */
/* Release postmaster's working memory context */
MemoryContextSwitchTo(TopMemoryContext);
MemoryContextDelete(PostmasterContext);
PostmasterContext = NULL;
AuxiliaryProcessMain(ac, av);
ExitPostmaster(0);
}

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;
}

InitPostmasterChild

InitPostmasterChild函数将IsUnderPostmaster设置为true,也就是postmaster的子进程。重置proc_exit proc_exit,初始化进程本地latch支持。调用PostmasterDeathSignalInit注册postmaster death信号处理函数。

信号

信号处理函数

功能

POSTMASTER_DEATH_SIGNAL

postmaster_death_handler

子进程处理postmaster death信号(部分平台支持)

void InitPostmasterChild(void) {
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
InitProcessGlobals();
on_exit_reset(); /* We don't want the postmaster's proc_exit() handlers */

/* Initialize process-local latch support */
InitializeLatchSupport();
MyLatch = &LocalLatchData;
InitLatch(MyLatch);

/* If possible, make this process a group leader, so that the postmaster
* can signal any child processes too. Not all processes will have
* children, but for consistency we make all postmaster child processes do
* this. */
#ifdef HAVE_SETSID
if (setsid() < 0) elog(FATAL, "setsid() failed: %m");
#endif

/* Request a signal if the postmaster dies, if possible. */
PostmasterDeathSignalInit();
}

ClosePostmasterPorts

AuxiliaryProcessMain

处理argv命令行参数

AuxiliaryProcessMain(int argc, char *argv[]) {
char *progname = argv[0];
int flag; char *userDoption = NULL;
...
/* Ignore the initial --boot argument, if present */
if (argc > 1 && strcmp(argv[1], "--boot") == 0) {
argv++; argc--;
}
/* If no -x argument, we are a CheckerProcess */
MyAuxProcType = CheckerProcess;
while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:X:-:")) != -1) {
switch (flag) {
case 'B': SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV); break;
case 'D': userDoption = pstrdup(optarg); break;
case 'd': { /* Turn on debugging for the bootstrap process. */
char *debugstr;
debugstr = psprintf("debug%s", optarg);
SetConfigOption("log_min_messages", debugstr, PGC_POSTMASTER, PGC_S_ARGV);
SetConfigOption("client_min_messages", debugstr, PGC_POSTMASTER, PGC_S_ARGV);
pfree(debugstr);
}
break;
case 'F': SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV); break;
case 'k': bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION; break;
case 'r': strlcpy(OutputFileName, optarg, MAXPGPATH); break;
case 'x': MyAuxProcType = atoi(optarg); break;
case 'X':{
int WalSegSz = strtoul(optarg, NULL, 0);
if (!IsValidWalSegSize(WalSegSz)) ereport(ERROR,(errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("-X requires a power of two value between 1 MB and 1 GB")));
SetConfigOption("wal_segment_size", optarg, PGC_INTERNAL, PGC_S_OVERRIDE);
}
break;
case 'c':
case '-': {
char *name, *value;
ParseLongOption(optarg, &name, &value);
if (!value) {
if (flag == '-') ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),errmsg("--%s requires a value",optarg)));
else ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),errmsg("-c %s requires a value",optarg)));
}
SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV); free(name);
if (value) free(value);
break;
}
default:
write_stderr("Try \"%s --help\" for more information.\n", progname); proc_exit(1); break;
}
}
if (argc != optind) {
write_stderr("%s: invalid command-line arguments\n", progname); proc_exit(1);
}

通过ps显示自己的进程情况

/* Identify myself via ps */
if (IsUnderPostmaster){
const char *statmsg;
switch (MyAuxProcType){
case StartupProcess:statmsg = pgstat_get_backend_desc(B_STARTUP);break;
case BgWriterProcess:statmsg = pgstat_get_backend_desc(B_BG_WRITER);break;
case CheckpointerProcess:statmsg = pgstat_get_backend_desc(B_CHECKPOINTER);break;
case WalWriterProcess:statmsg = pgstat_get_backend_desc(B_WAL_WRITER);break;
case WalReceiverProcess:statmsg = pgstat_get_backend_desc(B_WAL_RECEIVER);break;
default:statmsg = "??? process";break;
}
init_ps_display(statmsg, "", "", "");
}

子进程环境初始化

BaseInit函数在standalone或under postmaster进行初期初始化后端backend,且是在InitPostgres之前执行。主要调用如下函数:InitCommunication、DebugFileOpen、InitFileAccess、InitSync、smgrinit、InitBufferPoolAccess。

SetProcessingMode(BootstrapProcessing);
IgnoreSystemIndexes = true;
...
BaseInit();

在auxiliary process中不能像后端postgres一样直接执行InitPostgres进行初始化,需要执行另外的函数进行初始化。

/* When we are an auxiliary process, we aren't going to do the full
* InitPostgres pushups, but there are a couple of things that need to get
* lit up even in an auxiliary process. */
if (IsUnderPostmaster) {
/* Assign the ProcSignalSlot for an auxiliary process. Since it
* doesn't have a BackendId, the slot is statically allocated based on
* the auxiliary process type (MyAuxProcType). Backends use slots
* indexed in the range from 1 to MaxBackends (inclusive), so we use
* MaxBackends + AuxProcType + 1 as the index of the slot for an
* auxiliary process.
* This will need rethinking if we ever want more than one of a
* particular auxiliary process type. */
ProcSignalInit(MaxBackends + MyAuxProcType + 1);

InitBufferPoolBackend(); /* finish setting up bufmgr.c */
/* Auxiliary processes don't run transactions, but they may need a
* resource owner anyway to manage buffer pins acquired outside
* transactions (and, perhaps, other things in future). */
CreateAuxProcessResourceOwner();

pgstat_initialize(); /* Initialize backend status information */
pgstat_bestart();
before_shmem_exit(ShutdownAuxiliaryProcess, 0); /* register a before-shutdown callback for LWLock cleanup */
}

ProcSignalInit函数在procsignal数组中注册当前进程。传入参数可以是后台进行的BackendId,或者是MaxBackends + aux process type。函数执行流程参考PostgreSQL数据库PMsignal——后端进程\Postmaster信号通信中的进程间信号通信。

BootstrapProcess

/* XLOG operations */
SetProcessingMode(NormalProcessing);
switch (MyAuxProcType){
case StartupProcess:
/* don't set signals, startup process has its own agenda */
StartupProcessMain();
proc_exit(1); /* should never return */

StartupProcessMain函数

StartupProcessMain函数主要工作是注册信号处理函数、PG_SETMASK(&UnBlockSig)和运行StartupXLOG函数。

信号

信号处理函数

功能

SIGHUP

StartupProcSigHupHandler

重载配置文件

SIGINT

SIG_IGN

忽略查询取消

SIGTERM

StartupProcShutdownHandler

request shutdown

SIGQUIT

startupproc_quickdie

hard crash time

SIGALRM

handle_sig_alarm

timeout

SIGPIPE

SIG_IGN

SIGUSR1

StartupProcSigUsr1Handler

SIGUSR2

StartupProcTriggerHandler

SIGCHLD

SIG_DFL

STANDBY_DEADLOCK_TIMEOUT

StandbyDeadLockHandler

STANDBY_TIMEOUT

StandbyTimeoutHandler

STANDBY_LOCK_TIMEOUT

StandbyLockTimeoutHandler

StartupXLOG
proc_exit(0)

PG守护进程(Postmaster)——后台一等公民进程StartupDataBase_初始化