📄 postmaster.c
字号:
/* Tell pgarch to shut down too; nothing left for it to do */ if (PgArchPID != 0) kill(PgArchPID, SIGQUIT); /* Tell pgstat to shut down too; nothing left for it to do */ if (PgStatPID != 0) kill(PgStatPID, SIGQUIT); break; case SIGQUIT: /* * Immediate Shutdown: * * abort all children with SIGQUIT and exit without attempt to * properly shut down data base system. */ ereport(LOG, (errmsg("received immediate shutdown request"))); if (StartupPID != 0) kill(StartupPID, SIGQUIT); if (BgWriterPID != 0) kill(BgWriterPID, SIGQUIT); if (AutoVacPID != 0) kill(AutoVacPID, SIGQUIT); if (PgArchPID != 0) kill(PgArchPID, SIGQUIT); if (PgStatPID != 0) kill(PgStatPID, SIGQUIT); if (DLGetHead(BackendList)) SignalChildren(SIGQUIT); ExitPostmaster(0); break; } PG_SETMASK(&UnBlockSig); errno = save_errno;}/* * Reaper -- signal handler to cleanup after a backend (child) dies. */static voidreaper(SIGNAL_ARGS){ int save_errno = errno;#ifdef HAVE_WAITPID int status; /* backend exit status */#else#ifndef WIN32 union wait status; /* backend exit status */#endif#endif int exitstatus; int pid; /* process id of dead backend */ PG_SETMASK(&BlockSig); ereport(DEBUG4, (errmsg_internal("reaping dead processes")));#ifdef HAVE_WAITPID while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { exitstatus = status;#else#ifndef WIN32 while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { exitstatus = status.w_status;#else while ((pid = win32_waitpid(&exitstatus)) > 0) { /* * We need to do this here, and not in CleanupBackend, since this is * to be called on all children when we are done with them. Could move * to LogChildExit, but that seems like asking for future trouble... */ win32_RemoveChild(pid);#endif /* WIN32 */#endif /* HAVE_WAITPID */ /* * Check if this child was a startup process. */ if (StartupPID != 0 && pid == StartupPID) { StartupPID = 0; if (exitstatus != 0) { LogChildExit(LOG, _("startup process"), pid, exitstatus); ereport(LOG, (errmsg("aborting startup due to startup process failure"))); ExitPostmaster(1); } /* * Startup succeeded - we are done with system startup or * recovery. */ FatalError = false; /* * Load the flat authorization file into postmaster's cache. The * startup process has recomputed this from the database contents, * so we wait till it finishes before loading it. */ load_role(); /* * Crank up the background writer. It doesn't matter if this * fails, we'll just try again later. */ Assert(BgWriterPID == 0); BgWriterPID = StartBackgroundWriter(); /* * Go to shutdown mode if a shutdown request was pending. * Otherwise, try to start the archiver and stats collector too. * (We could, but don't, try to start autovacuum here.) */ if (Shutdown > NoShutdown && BgWriterPID != 0) kill(BgWriterPID, SIGUSR2); else if (Shutdown == NoShutdown) { if (XLogArchivingActive() && PgArchPID == 0) PgArchPID = pgarch_start(); if (PgStatPID == 0) PgStatPID = pgstat_start(); } continue; } /* * Was it the bgwriter? */ if (BgWriterPID != 0 && pid == BgWriterPID) { BgWriterPID = 0; if (exitstatus == 0 && Shutdown > NoShutdown && !FatalError && !DLGetHead(BackendList) && AutoVacPID == 0) { /* * Normal postmaster exit is here: we've seen normal exit of * the bgwriter after it's been told to shut down. We expect * that it wrote a shutdown checkpoint. (If for some reason * it didn't, recovery will occur on next postmaster start.) * * Note: we do not wait around for exit of the archiver or * stats processes. They've been sent SIGQUIT by this point, * and in any case contain logic to commit hara-kiri if they * notice the postmaster is gone. */ ExitPostmaster(0); } /* * Any unexpected exit of the bgwriter is treated as a crash. */ HandleChildCrash(pid, exitstatus, _("background writer process")); continue; } /* * Was it the autovacuum process? Normal exit can be ignored; we'll * start a new one at the next iteration of the postmaster's main * loop, if necessary. * * An unexpected exit must crash the system. */ if (AutoVacPID != 0 && pid == AutoVacPID) { AutoVacPID = 0; autovac_stopped(); /* Tell the collector about process termination */ pgstat_beterm(pid); if (exitstatus != 0) HandleChildCrash(pid, exitstatus, _("autovacuum process")); continue; } /* * Was it the archiver? If so, just try to start a new one; no need * to force reset of the rest of the system. (If fail, we'll try * again in future cycles of the main loop.) */ if (PgArchPID != 0 && pid == PgArchPID) { PgArchPID = 0; if (exitstatus != 0) LogChildExit(LOG, _("archiver process"), pid, exitstatus); if (XLogArchivingActive() && StartupPID == 0 && !FatalError && Shutdown == NoShutdown) PgArchPID = pgarch_start(); continue; } /* * Was it the statistics collector? If so, just try to start a new * one; no need to force reset of the rest of the system. (If fail, * we'll try again in future cycles of the main loop.) */ if (PgStatPID != 0 && pid == PgStatPID) { PgStatPID = 0; if (exitstatus != 0) LogChildExit(LOG, _("statistics collector process"), pid, exitstatus); if (StartupPID == 0 && !FatalError && Shutdown == NoShutdown) PgStatPID = pgstat_start(); continue; } /* Was it the system logger? try to start a new one */ if (SysLoggerPID != 0 && pid == SysLoggerPID) { SysLoggerPID = 0; /* for safety's sake, launch new logger *first* */ SysLoggerPID = SysLogger_Start(); if (exitstatus != 0) LogChildExit(LOG, _("system logger process"), pid, exitstatus); continue; } /* * Else do standard backend child cleanup. */ CleanupBackend(pid, exitstatus); } /* loop over pending child-death reports */ if (FatalError) { /* * Wait for all important children to exit, then reset shmem and * StartupDataBase. (We can ignore the archiver and stats processes * here since they are not connected to shmem.) */ if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0 || AutoVacPID != 0) goto reaper_done; ereport(LOG, (errmsg("all server processes terminated; reinitializing"))); shmem_exit(0); reset_shared(PostPortNumber); StartupPID = StartupDataBase(); goto reaper_done; } if (Shutdown > NoShutdown) { if (DLGetHead(BackendList) || StartupPID != 0 || AutoVacPID != 0) goto reaper_done; /* Start the bgwriter if not running */ if (BgWriterPID == 0) BgWriterPID = StartBackgroundWriter(); /* And tell it to shut down */ if (BgWriterPID != 0) kill(BgWriterPID, SIGUSR2); /* Tell pgarch to shut down too; nothing left for it to do */ if (PgArchPID != 0) kill(PgArchPID, SIGQUIT); /* Tell pgstat to shut down too; nothing left for it to do */ if (PgStatPID != 0) kill(PgStatPID, SIGQUIT); }reaper_done: PG_SETMASK(&UnBlockSig); errno = save_errno;}/* * CleanupBackend -- cleanup after terminated backend. * * Remove all local state associated with backend. */static voidCleanupBackend(int pid, int exitstatus) /* child's exit status. */{ Dlelem *curr; LogChildExit(DEBUG2, _("server process"), pid, exitstatus); /* * If a backend dies in an ugly way (i.e. exit status not 0) then we must * signal all other backends to quickdie. If exit status is zero we * assume everything is hunky dory and simply remove the backend from the * active backend list. */ if (exitstatus != 0) { HandleChildCrash(pid, exitstatus, _("server process")); return; } for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr)) { Backend *bp = (Backend *) DLE_VAL(curr); if (bp->pid == pid) { DLRemove(curr); free(bp); DLFreeElem(curr);#ifdef EXEC_BACKEND ShmemBackendArrayRemove(pid);#endif /* Tell the collector about backend termination */ pgstat_beterm(pid); break; } }}/* * HandleChildCrash -- cleanup after failed backend, bgwriter, or autovacuum. * * The objectives here are to clean up our local state about the child * process, and to signal all other remaining children to quickdie. */static voidHandleChildCrash(int pid, int exitstatus, const char *procname){ Dlelem *curr, *next; Backend *bp; /* * Make log entry unless there was a previous crash (if so, nonzero exit * status is to be expected in SIGQUIT response; don't clutter log) */ if (!FatalError) { LogChildExit(LOG, procname, pid, exitstatus); ereport(LOG, (errmsg("terminating any other active server processes"))); } /* Process regular backends */ for (curr = DLGetHead(BackendList); curr; curr = next) { next = DLGetSucc(curr); bp = (Backend *) DLE_VAL(curr); if (bp->pid == pid) { /* * Found entry for freshly-dead backend, so remove it. */ DLRemove(curr); free(bp); DLFreeElem(curr);#ifdef EXEC_BACKEND ShmemBackendArrayRemove(pid);#endif /* Tell the collector about backend termination */ pgstat_beterm(pid); /* Keep looping so we can signal remaining backends */ } else { /* * This backend is still alive. Unless we did so already, tell it * to commit hara-kiri. * * SIGQUIT is the special signal that says exit without proc_exit * and let the user know what's going on. But if SendStop is set * (-s on command line), then we send SIGSTOP instead, so that we * can get core dumps from all backends by hand. */ if (!FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) bp->pid))); kill(bp->pid, (SendStop ? SIGSTOP : SIGQUIT)); } } } /* Take care of the bgwriter too */ if (pid == BgWriterPID) BgWriterPID = 0; else if (BgWriterPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) BgWriterPID))); kill(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT)); } /* Take care of the autovacuum daemon too */ if (pid == AutoVacPID) AutoVacPID = 0; else if (AutoVacPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) AutoVacPID))); kill(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT)); } /* Force a power-cycle of the pgarch process too */ /* (Shouldn't be necessary, but just for luck) */ if (PgArchPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", "SIGQUIT", (int) PgArchPID))); kill(PgArchPID, SIGQUIT); } /* Force a power-cycle of the pgstat processes too */ /* (Shouldn't be necessary, but just for luck) */ if (PgStatPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", "SIGQUIT", (int) PgStatPID))); kill(PgStatPID, SIGQUIT); } /* We do NOT restart the syslogger */ FatalError = true;}/* * Log the death of a child process. */static voidLogChildExit(int lev, const char *procname, int pid, int exitstatus){ if (WIFEXITED(exitstatus)) ereport(lev, /* * translator: %s is a noun phrase describing a child process, such as * "server process" */ (errmsg("%s (PID %d) exited with exit code %d", procname, pid, WEXITSTATUS(exitstatus)))); else if (WIFSIGNALED(exitstatus)) ereport(lev, /* * translator: %s is a noun phrase describing a child process, such as * "server process" */ (errmsg("%s (PID %d) was terminated by signal %d", procname, pid, WTERMSIG(exitstatus)))); else ereport(lev, /* * translator: %s is a noun phrase describing a child process, such as * "server process" */ (errmsg("%s (PID %d) exited with unexpected status %d", procname, pid, exitstatus)));}/* * Send a signal to all backend children (but NOT special children) */static voidSignalChildren(int signal){ Dlelem *curr; for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(cu
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -