📄 postmaster.c
字号:
return CAC_SHUTDOWN; if (StartupPID) return CAC_STARTUP; if (FatalError) return CAC_RECOVERY; /* * Don't start too many children. * * We allow more connections than we can have backends here because some * might still be authenticating; they might fail auth, or some * existing backend might exit before the auth cycle is completed. The * exact MaxBackends limit is enforced when a new backend tries to * join the shared-inval backend array. */ if (CountChildren() >= 2 * MaxBackends) return CAC_TOOMANY; return CAC_OK;}/* * ConnCreate -- create a local connection data structure */static Port *ConnCreate(int serverFd){ Port *port; if (!(port = (Port *) calloc(1, sizeof(Port)))) { ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); ExitPostmaster(1); } if (StreamConnection(serverFd, port) != STATUS_OK) { StreamClose(port->sock); ConnFree(port); port = NULL; } else { /* * Precompute password salt values to use for this connection. * It's slightly annoying to do this long in advance of knowing * whether we'll need 'em or not, but we must do the random() * calls before we fork, not after. Else the postmaster's random * sequence won't get advanced, and all backends would end up * using the same salt... */ RandomSalt(port->cryptSalt, port->md5Salt); } return port;}/* * ConnFree -- free a local connection data structure */static voidConnFree(Port *conn){#ifdef USE_SSL secure_close(conn);#endif free(conn);}/* * ClosePostmasterPorts -- close all the postmaster's open sockets * * This is called during child process startup to release file descriptors * that are not needed by that child process. The postmaster still has * them open, of course. */voidClosePostmasterPorts(bool pgstat_too){ int i; /* Close the listen sockets */ for (i = 0; i < MAXLISTEN; i++) { if (ListenSocket[i] != -1) { StreamClose(ListenSocket[i]); ListenSocket[i] = -1; } } /* Close pgstat control sockets, unless we're starting pgstat itself */ if (pgstat_too) pgstat_close_sockets();}/* * reset_shared -- reset shared memory and semaphores */static voidreset_shared(unsigned short port){ /* * Create or re-create shared memory and semaphores. * * Note: in each "cycle of life" we will normally assign the same IPC * keys (if using SysV shmem and/or semas), since the port number is * used to determine IPC keys. This helps ensure that we will clean * up dead IPC objects if the postmaster crashes and is restarted. */ CreateSharedMemoryAndSemaphores(false, MaxBackends, port);}/* * SIGHUP -- reread config files, and tell children to do same */static voidSIGHUP_handler(SIGNAL_ARGS){ int save_errno = errno; PG_SETMASK(&BlockSig); if (Shutdown <= SmartShutdown) { ereport(LOG, (errmsg("received SIGHUP, reloading configuration files"))); ProcessConfigFile(PGC_SIGHUP);#ifdef EXEC_BACKEND write_nondefault_variables(PGC_SIGHUP);#endif SignalChildren(SIGHUP); load_hba(); load_ident(); } PG_SETMASK(&UnBlockSig); errno = save_errno;}/* * pmdie -- signal handler for processing various postmaster signals. */static voidpmdie(SIGNAL_ARGS){ int save_errno = errno; PG_SETMASK(&BlockSig); ereport(DEBUG2, (errmsg_internal("postmaster received signal %d", postgres_signal_arg))); switch (postgres_signal_arg) { case SIGTERM: /* * Smart Shutdown: * * Wait for children to end their work and ShutdownDataBase. */ if (Shutdown >= SmartShutdown) break; Shutdown = SmartShutdown; ereport(LOG, (errmsg("received smart shutdown request"))); if (DLGetHead(BackendList)) /* let reaper() handle this */ break; /* * No children left. Shutdown data base system. */ if (StartupPID > 0 || FatalError) /* let reaper() handle * this */ break; if (ShutdownPID > 0) { elog(PANIC, "shutdown process %d already running", (int) ShutdownPID); abort(); } ShutdownPID = ShutdownDataBase(); break; case SIGINT: /* * Fast Shutdown: * * abort all children with SIGTERM (rollback active transactions * and exit) and ShutdownDataBase when they are gone. */ if (Shutdown >= FastShutdown) break; ereport(LOG, (errmsg("received fast shutdown request"))); if (DLGetHead(BackendList)) /* let reaper() handle this */ { Shutdown = FastShutdown; if (!FatalError) { ereport(LOG, (errmsg("aborting any active transactions"))); SignalChildren(SIGTERM); } break; } if (Shutdown > NoShutdown) { Shutdown = FastShutdown; break; } Shutdown = FastShutdown; /* * No children left. Shutdown data base system. */ if (StartupPID > 0 || FatalError) /* let reaper() handle * this */ break; if (ShutdownPID > 0) { elog(PANIC, "shutdown process %d already running", (int) ShutdownPID); abort(); } ShutdownPID = ShutdownDataBase(); break; case SIGQUIT: /* * Immediate Shutdown: * * abort all children with SIGQUIT and exit without attempt to * properly shutdown data base system. */ ereport(LOG, (errmsg("received immediate shutdown request"))); if (ShutdownPID > 0) kill(ShutdownPID, SIGQUIT); if (StartupPID > 0) kill(StartupPID, 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 WIN32#warning fix waidpid for Win32#else#ifdef HAVE_WAITPID int status; /* backend exit status */#else union wait status; /* backend exit status */#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 while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { exitstatus = status.w_status;#endif /* * Check if this child was the statistics collector. If so, try to * start a new one. (If fail, we'll try again in future cycles of * the main loop.) */ if (pgstat_ispgstat(pid)) { LogChildExit(LOG, gettext("statistics collector process"), pid, exitstatus); pgstat_start(); continue; } /* * Check if this child was a shutdown or startup process. */ if (ShutdownPID > 0 && pid == ShutdownPID) { if (exitstatus != 0) { LogChildExit(LOG, gettext("shutdown process"), pid, exitstatus); ExitPostmaster(1); } /* Normal postmaster exit is here */ ExitPostmaster(0); } if (StartupPID > 0 && pid == StartupPID) { if (exitstatus != 0) { LogChildExit(LOG, gettext("startup process"), pid, exitstatus); ereport(LOG, (errmsg("aborting startup due to startup process failure"))); ExitPostmaster(1); } StartupPID = 0; /* * Startup succeeded - remember its ID and RedoRecPtr. * * NB: this MUST happen before we fork a checkpoint or shutdown * subprocess, else they will have wrong local ThisStartUpId. */ SetThisStartUpID(); FatalError = false; /* done with recovery */ /* * Arrange for first checkpoint to occur after standard delay. */ CheckPointPID = 0; checkpointed = time(NULL); /* * Go to shutdown mode if a shutdown request was pending. */ if (Shutdown > NoShutdown) { if (ShutdownPID > 0) { elog(PANIC, "startup process %d died while shutdown process %d already running", pid, (int) ShutdownPID); abort(); } ShutdownPID = ShutdownDataBase(); } goto reaper_done; } /* * Else do standard child cleanup. */ CleanupProc(pid, exitstatus); } /* loop over pending child-death reports */#endif if (FatalError) { /* * Wait for all children exit, then reset shmem and * StartupDataBase. */ if (DLGetHead(BackendList) || StartupPID > 0 || ShutdownPID > 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)) goto reaper_done; if (StartupPID > 0 || ShutdownPID > 0) goto reaper_done; ShutdownPID = ShutdownDataBase(); }reaper_done: PG_SETMASK(&UnBlockSig); errno = save_errno;}/* * CleanupProc -- cleanup after terminated backend. * * Remove all local state associated with backend. */static voidCleanupProc(int pid, int exitstatus) /* child's exit status. */{ Dlelem *curr, *next; Backend *bp; LogChildExit(DEBUG2, gettext("child 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) { curr = DLGetHead(BackendList); while (curr) { bp = (Backend *) DLE_VAL(curr); if (bp->pid == pid) { DLRemove(curr); free(bp); DLFreeElem(curr); break; } curr = DLGetSucc(curr); } if (pid == CheckPointPID) { CheckPointPID = 0; if (!FatalError) { checkpointed = time(NULL); /* Update RedoRecPtr for future child backends */ GetSavedRedoRecPtr(); } } else pgstat_beterm(pid); return; } /* below here we're dealing with a non-normal exit */ /* Make log entry unless we did so already */ if (!FatalError) { LogChildExit(LOG, (pid == CheckPointPID) ? gettext("checkpoint process") : gettext("server process"), pid, exitstatus); ereport(LOG, (errmsg("terminating any other active server processes"))); } curr = DLGetHead(BackendList); while (curr) { next = DLGetSucc(curr); bp = (Backend *) DLE_VAL(curr); if (bp->pid != pid) { /* * 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)); } } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -