/* Startup process's status */ typedefenum
{
STARTUP_NOT_RUNNING,
STARTUP_RUNNING,
STARTUP_SIGNALED, /* we sent it a SIGQUIT or SIGKILL */
STARTUP_CRASHED,
} StartupStatusEnum;
/* Macros to check exit status of a child process */ #define EXIT_STATUS_0(st) ((st) == 0) #define EXIT_STATUS_1(st) (WIFEXITED(st) && WEXITSTATUS(st) == 1) #define EXIT_STATUS_3(st) (WIFEXITED(st) && WEXITSTATUS(st) == 3)
#ifndef WIN32 /* *Filedescriptorsforpipeusedtomonitorifpostmasterisalive. *FirstisPOSTMASTER_FD_WATCH,secondisPOSTMASTER_FD_OWN.
*/ int postmaster_alive_fds[2] = {-1, -1}; #else /* Process handle of postmaster used for the same purpose on Windows */
HANDLE PostmasterHandle; #endif
/* *Erroriftheusermisplacedaspecialmust-be-firstoption *fordispatchingtoasubprogram.parse_dispatch_option() *returnsDISPATCH_POSTMASTERifitdoesn'tfindamatch,so *errorforanythingelse.
*/ if (parse_dispatch_option(optarg) != DISPATCH_POSTMASTER)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("--%s must be first argument", optarg)));
/* FALLTHROUGH */ case'c':
{ char *name,
*value;
ParseLongOption(optarg, &name, &value); if (!value)
{ if (opt == '-')
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)));
}
/* Verify that DataDir looks reasonable */
checkDataDir();
/* Check that pg_control exists */
checkControlFile();
/* And switch working directory into it */
ChangeToDataDir();
/* *CheckforinvalidcombinationsofGUCsettings.
*/ if (SuperuserReservedConnections + ReservedConnections >= MaxConnections)
{
write_stderr("%s: \"superuser_reserved_connections\" (%d) plus \"reserved_connections\" (%d) must be less than \"max_connections\" (%d)\n",
progname,
SuperuserReservedConnections, ReservedConnections,
MaxConnections);
ExitPostmaster(1);
} if (XLogArchiveMode > ARCHIVE_MODE_OFF && wal_level == WAL_LEVEL_MINIMAL)
ereport(ERROR,
(errmsg("WAL archival cannot be enabled when \"wal_level\" is \"minimal\""))); if (max_wal_senders > 0 && wal_level == WAL_LEVEL_MINIMAL)
ereport(ERROR,
(errmsg("WAL streaming (\"max_wal_senders\" > 0) requires \"wal_level\" to be \"replica\" or \"logical\""))); if (summarize_wal && wal_level == WAL_LEVEL_MINIMAL)
ereport(ERROR,
(errmsg("WAL cannot be summarized when \"wal_level\" is \"minimal\"")));
/* *Nowthatwearedoneprocessingthepostmasterarguments,reset *getopt(3)librarysothatitwillworkcorrectlyinsubprocesses.
*/
optind = 1; #ifdef HAVE_INT_OPTRESET
optreset = 1; /* some systems need this too */ #endif
if (ListenAddresses)
{ char *rawstring;
List *elemlist;
ListCell *l; int success = 0;
/* Need a modifiable copy of ListenAddresses */
rawstring = pstrdup(ListenAddresses);
/* Parse string into list of hostnames */ if (!SplitGUCList(rawstring, ',', &elemlist))
{ /* syntax error in list */
ereport(FATAL,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid list syntax in parameter \"%s\"", "listen_addresses")));
}
if (strcmp(curhost, "*") == 0)
status = ListenServerPort(AF_UNSPEC, NULL,
(unsignedshort) PostPortNumber,
NULL,
ListenSockets,
&NumListenSockets,
MAXLISTEN); else
status = ListenServerPort(AF_UNSPEC, curhost,
(unsignedshort) PostPortNumber,
NULL,
ListenSockets,
&NumListenSockets,
MAXLISTEN);
if (status == STATUS_OK)
{
success++; /* record the first successful host addr in lockfile */ if (!listen_addr_saved)
{
AddToDataDirLockFile(LOCK_FILE_LINE_LISTEN_ADDR, curhost);
listen_addr_saved = true;
}
} else
ereport(WARNING,
(errmsg("could not create listen socket for \"%s\"",
curhost)));
}
if (!success && elemlist != NIL)
ereport(FATAL,
(errmsg("could not create any TCP/IP sockets")));
list_free(elemlist);
pfree(rawstring);
}
#ifdef USE_BONJOUR /* Register for Bonjour only if we opened TCP socket(s) */ if (enable_bonjour && NumListenSockets > 0)
{
DNSServiceErrorType err;
if (Unix_socket_directories)
{ char *rawstring;
List *elemlist;
ListCell *l; int success = 0;
/* Need a modifiable copy of Unix_socket_directories */
rawstring = pstrdup(Unix_socket_directories);
/* Parse string into list of directories */ if (!SplitDirectoriesString(rawstring, ',', &elemlist))
{ /* syntax error in list */
ereport(FATAL,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid list syntax in parameter \"%s\"", "unix_socket_directories")));
}
status = ListenServerPort(AF_UNIX, NULL,
(unsignedshort) PostPortNumber,
socketdir,
ListenSockets,
&NumListenSockets,
MAXLISTEN);
if (status == STATUS_OK)
{
success++; /* record the first successful Unix socket in lockfile */ if (success == 1)
AddToDataDirLockFile(LOCK_FILE_LINE_SOCKET_DIR, socketdir);
} else
ereport(WARNING,
(errmsg("could not create Unix-domain socket in directory \"%s\"",
socketdir)));
}
if (!success && elemlist != NIL)
ereport(FATAL,
(errmsg("could not create any Unix-domain sockets")));
list_free_deep(elemlist);
pfree(rawstring);
}
/* *checkthatwehavesomesockettolistenon
*/ if (NumListenSockets == 0)
ereport(FATAL,
(errmsg("no socket created for listening")));
/* *IfnovalidTCPports,writeanemptylineforlistenaddress, *indicatingtheUnixsocketmustbeused.Notethatthislineisnot *addedtothelockfileuntilthereisasocketbackingit.
*/ if (!listen_addr_saved)
AddToDataDirLockFile(LOCK_FILE_LINE_LISTEN_ADDR, "");
/* *Recordpostmasteroptions.Wedelaythistillnowtoavoidrecording *bogusoptions(eg,unusableportnumber).
*/ if (!CreateOptsFile(argc, argv, my_exec_path))
ExitPostmaster(1);
/* Make sure we can perform I/O while starting up. */
maybe_adjust_io_workers();
/* Start bgwriter and checkpointer so they can help with recovery */ if (CheckpointerPMChild == NULL)
CheckpointerPMChild = StartChildProcess(B_CHECKPOINTER); if (BgWriterPMChild == NULL)
BgWriterPMChild = StartChildProcess(B_BG_WRITER);
/* *on_proc_exitcallbacktocloseserver'slistensockets
*/ staticvoid
CloseServerPorts(int status, Datum arg)
{ int i;
/* *First,explicitlycloseallthesocketFDs.Weusedtojustletthis *happenimplicitlyatpostmasterexit,butit'sbettertoclosethem *beforeweremovethepostmaster.pidlockfile;otherwisethere'sarace *conditionifanewpostmasterwantstore-usetheTCPportnumber.
*/ for (i = 0; i < NumListenSockets; i++)
{ if (closesocket(ListenSockets[i]) != 0)
elog(LOG, "could not close listen socket: %m");
}
NumListenSockets = 0;
/* *on_proc_exitcallbacktodeleteexternal_pid_file
*/ staticvoid
unlink_external_pid_file(int status, Datum arg)
{ if (external_pid_file)
unlink(external_pid_file);
}
/* *Computeandcheckthedirectorypathstofilesthatarepartofthe *installation(asdeducedfromthepostgresexecutable'sownlocation)
*/ staticvoid
getInstallationPaths(constchar *argv0)
{
DIR *pdir;
/* Locate the postgres executable itself */ if (find_my_exec(argv0, my_exec_path) < 0)
ereport(FATAL,
(errmsg("%s: could not locate my own executable path", argv0)));
#ifdef EXEC_BACKEND /* Locate executable backend before we change working directory */ if (find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
postgres_exec_path) < 0)
ereport(FATAL,
(errmsg("%s: could not locate matching postgres executable",
argv0))); #endif
/* *Verifythatthere'sareadabledirectorythere;otherwisethePostgres *installationisincompleteorcorrupt.(Atypicalcauseofthis *failureisthatthepostgresexecutablehasbeenmovedorhardlinkedto *somedirectorythat'snotasiblingoftheinstallationlib/ *directory.)
*/
pdir = AllocateDir(pkglib_path); if (pdir == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m",
pkglib_path),
errhint("This may indicate an incomplete PostgreSQL installation, or that the file \"%s\" has been moved away from its proper location.",
my_exec_path)));
FreeDir(pdir);
fp = AllocateFile(path, PG_BINARY_R); if (fp == NULL)
{
write_stderr("%s: could not find the database system\n" "Expected to find it in the directory \"%s\",\n" "but could not open file \"%s\": %m\n",
progname, DataDir, path);
ExitPostmaster(2);
}
FreeFile(fp);
}
/* result of TimestampDifferenceMilliseconds is in [0, INT_MAX] */
ms = (int) TimestampDifferenceMilliseconds(GetCurrentTimestamp(),
next_wakeup); return Min(60 * 1000, ms);
}
if (accept_connections)
{ for (int i = 0; i < NumListenSockets; i++)
AddWaitEventToSet(pm_wait_set, WL_SOCKET_ACCEPT, ListenSockets[i],
NULL, NULL);
}
}
/* *Latchsetbysignalhandler,ornewconnectionpendingonanyof *oursockets?Ifthelatter,forkachildprocesstodealwithit.
*/ for (int i = 0; i < nevents; i++)
{ if (events[i].events & WL_LATCH_SET)
ResetLatch(MyLatch);
/* *Thefollowingrequestsarehandledunconditionally,evenifwe *didn'tseeWL_LATCH_SET.Thisgiveshighprioritytoshutdown *andreloadrequestswherethelatchhappenstoappearlaterin *events[]orwillbereportedbyalatercallto *WaitEventSetWait().
*/ if (pending_pm_shutdown_request)
process_pm_shutdown_request(); if (pending_pm_reload_request)
process_pm_reload_request(); if (pending_pm_child_exit)
process_pm_child_exit(); if (pending_pm_pmsignal)
process_pm_pmsignal();
if (events[i].events & WL_SOCKET_ACCEPT)
{
ClientSocket s;
if (AcceptConnection(events[i].fd, &s) == STATUS_OK)
BackendStartup(&s);
/* We no longer need the open socket in this process */ if (s.sock != PGINVALID_SOCKET)
{ if (closesocket(s.sock) != 0)
elog(LOG, "could not close client socket: %m");
}
}
}
/* If we need to signal the autovacuum launcher, do so now */ if (avlauncher_needs_signal)
{
avlauncher_needs_signal = false; if (AutoVacLauncherPMChild != NULL)
signal_child(AutoVacLauncherPMChild, SIGUSR2);
}
/* *Can'tstartbackendswheninstartup/shutdown/inconsistentrecovery *state.Wetreatautovacworkersthesameasuserbackendsforthis *purpose.
*/ if (pmState != PM_RUN && pmState != PM_HOT_STANDBY)
{ if (Shutdown > NoShutdown) return CAC_SHUTDOWN; /* shutdown is pending */ elseif (!FatalError && pmState == PM_STARTUP) return CAC_STARTUP; /* normal startup */ elseif (!FatalError && pmState == PM_RECOVERY) return CAC_NOTHOTSTANDBY; /* not yet ready for hot standby */ else return CAC_RECOVERY; /* else must be crash recovery */
}
/* *"Smartshutdown"restrictionsareappliedonlytonormalconnections, *nottoautovacworkers.
*/ if (!connsAllowed && backend_type == B_BACKEND) return CAC_SHUTDOWN; /* shutdown is pending */
return result;
}
/* *ClosePostmasterPorts--closeallthepostmaster'sopensockets * *Thisiscalledduringchildprocessstartuptoreleasefiledescriptors *thatarenotneededbythatchildprocess.Thepostmasterstillhas *themopen,ofcourse. * *Note:wepassam_sysloggerasabooleanbecausewedon'twanttoset *theglobalvariableyetwhenthisiscalled.
*/ void
ClosePostmasterPorts(bool am_syslogger)
{ /* Release resources held by the postmaster's WaitEventSet. */ if (pm_wait_set)
{
FreeWaitEventSetAfterFork(pm_wait_set);
pm_wait_set = NULL;
}
#ifndef WIN32
/* *Closethewriteendofpostmasterdeathwatchpipe.It'simportantto *dothisasearlyaspossible,sothatifpostmasterdies,otherswon't *thinkthatit'sstillrunningbecausewe'reholdingthepipeopen.
*/ if (close(postmaster_alive_fds[POSTMASTER_FD_OWN]) != 0)
ereport(FATAL,
(errcode_for_file_access(),
errmsg_internal("could not close postmaster death monitoring pipe in child process: %m")));
postmaster_alive_fds[POSTMASTER_FD_OWN] = -1; /* Notify fd.c that we released one pipe FD. */
ReleaseExternalFD(); #endif
/* *Closethepostmaster'slistensockets.Thesearen'ttrackedbyfd.c, *sowedon'tcallReleaseExternalFD()here. * *ThelistensocketsaremarkedasFD_CLOEXEC,sothisisn'tneededin *EXEC_BACKENDmode.
*/ #ifndef EXEC_BACKEND if (ListenSockets)
{ for (int i = 0; i < NumListenSockets; i++)
{ if (closesocket(ListenSockets[i]) != 0)
elog(LOG, "could not close listen socket: %m");
}
pfree(ListenSockets);
}
NumListenSockets = 0;
ListenSockets = NULL; #endif
/* *Ifusingsyslogger,closethereadsideofthepipe.Wedon'tbother *trackingthisinfd.c,either.
*/ if (!am_syslogger)
{ #ifndef WIN32 if (syslogPipe[0] >= 0)
close(syslogPipe[0]);
syslogPipe[0] = -1; #else if (syslogPipe[0])
CloseHandle(syslogPipe[0]);
syslogPipe[0] = 0; #endif
}
#ifdef USE_BONJOUR /* If using Bonjour, close the connection to the mDNS daemon */ if (bonjour_sdref)
close(DNSServiceRefSockFD(bonjour_sdref)); #endif
}
/* Reload authentication config files too */ if (!load_hba())
ereport(LOG, /* translator: %s is a configuration file */
(errmsg("%s was not reloaded", HbaFileName)));
if (!load_ident())
ereport(LOG,
(errmsg("%s was not reloaded", IdentFileName)));
#ifdef USE_SSL /* Reload SSL configuration as well */ if (EnableSSL)
{ if (secure_initialize(false) == 0)
LoadedSSL = true; else
ereport(LOG,
(errmsg("SSL configuration was not reloaded")));
} else
{
secure_destroy();
LoadedSSL = false;
} #endif
#ifdef EXEC_BACKEND /* Update the starting-point file for future children */
write_nondefault_variables(PGC_SIGHUP); #endif
}
}
/* *pg_ctlusesSIGTERM,SIGINTandSIGQUITtorequestdifferenttypesof *shutdown.
*/ staticvoid
handle_pm_shutdown_request_signal(SIGNAL_ARGS)
{ switch (postgres_signal_arg)
{ case SIGTERM: /* smart is implied if the other two flags aren't set */
pending_pm_shutdown_request = true; break; case SIGINT:
pending_pm_fast_shutdown_request = true;
pending_pm_shutdown_request = true; break; case SIGQUIT:
pending_pm_immediate_shutdown_request = true;
pending_pm_shutdown_request = true; break;
}
SetLatch(MyLatch);
}
/* *Processshutdownrequest.
*/ staticvoid
process_pm_shutdown_request(void)
{ int mode;
ereport(DEBUG2,
(errmsg_internal("postmaster received shutdown request signal")));
/* *Ifwereachednormalrunning,wegostraighttowaitingfor *clientbackendstoexit.IfalreadyinPM_STOP_BACKENDSora *laterstate,donotchangeit.
*/ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = false; elseif (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{ /* There should be no clients, so proceed to stop children */
UpdatePMState(PM_STOP_BACKENDS);
}
/* tell children to shut down ASAP */ /* (note we don't apply send_abort_for_crash here) */
SetQuitSignalReason(PMQUIT_FOR_STOP);
TerminateChildren(SIGQUIT);
UpdatePMState(PM_WAIT_BACKENDS);
/* set stopwatch for them to die */
AbortStartTime = time(NULL);
/* *Cleanupafterachildprocessdies.
*/ staticvoid
process_pm_child_exit(void)
{ int pid; /* process id of dead child process */ int exitstatus; /* its exit status */
pending_pm_child_exit = false;
ereport(DEBUG4,
(errmsg_internal("reaping dead processes")));
/* Was it the system logger? If so, try to start a new one */ if (SysLoggerPMChild && pid == SysLoggerPMChild->pid)
{
ReleasePostmasterChildSlot(SysLoggerPMChild);
SysLoggerPMChild = NULL;
/* for safety's sake, launch new logger *first* */ if (Logging_collector)
StartSysLogger();
if (!EXIT_STATUS_0(exitstatus))
LogChildExit(LOG, _("system logger process"),
pid, exitstatus); continue;
}
/* Was it an IO worker? */ if (maybe_reap_io_worker(pid))
{ if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus))
HandleChildCrash(pid, exitstatus, _("io worker"));
/* Construct a process name for the log message */ if (bp->bkend_type == B_BG_WORKER)
{
snprintf(namebuf, MAXPGPATH, _("background worker \"%s\""),
bp->rw->rw_worker.bgw_type);
procname = namebuf;
} else
procname = _(GetBackendTypeDesc(bp->bkend_type));
/* *ThisbackendmayhavebeenslatedtoreceiveSIGUSR1whensome *backgroundworkerstartedorstopped.Cancelthosenotifications,as *wedon'twanttosignalPIDsthatarenotPostgreSQLbackends.This *getsskippedinthe(probablyverycommon)casewherethebackendhas *neverrequestedanysuchnotifications.
*/ if (bp_bgworker_notify)
BackgroundWorkerStopNotifications(bp_pid);
/* *Ifitwasabackgroundworker,alsoupdateitsRegisteredBgWorker *entry.
*/ if (bp_bkend_type == B_BG_WORKER)
{ if (!EXIT_STATUS_0(exitstatus))
{ /* Record timestamp, so we know when to restart the worker. */
rw->rw_crashed_at = GetCurrentTimestamp();
} else
{ /* Zero exit status means terminate */
rw->rw_crashed_at = 0;
rw->rw_terminate = true;
}
rw->rw_pid = 0;
ReportBackgroundWorkerExit(rw); /* report child death */
/* *Choosetheappropriatenewstatetoreacttothefatalerror.Unlesswe *werealreadyintheprocessofshuttingdown,wegothrough *PM_WAIT_BACKENDS.Forerrorsduringtheshutdownsequence,wedirectly *switchtoPM_WAIT_DEAD_END.
*/ switch (pmState)
{ case PM_INIT: /* shouldn't have any children */
Assert(false); break;
/* wait for children to die */ case PM_STARTUP: case PM_RECOVERY: case PM_HOT_STANDBY: case PM_RUN: case PM_STOP_BACKENDS:
UpdatePMState(PM_WAIT_BACKENDS); break;
case PM_WAIT_BACKENDS: /* there might be more backends to wait for */ break;
case PM_WAIT_XLOG_SHUTDOWN: case PM_WAIT_XLOG_ARCHIVAL: case PM_WAIT_CHECKPOINTER: case PM_WAIT_IO_WORKERS:
/*------ translator:%sisanounphrasedescribingachildprocess,suchas
"server process" */
(errmsg("%s (PID %d) was terminated by exception 0x%X",
procname, pid, WTERMSIG(exitstatus)),
errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
activity ? errdetail("Failed process was running: %s", activity) : 0)); #else
ereport(lev,
/*------ translator:%sisanounphrasedescribingachildprocess,suchas
"server process" */
(errmsg("%s (PID %d) was terminated by signal %d: %s",
procname, pid, WTERMSIG(exitstatus),
pg_strsignal(WTERMSIG(exitstatus))),
activity ? errdetail("Failed process was running: %s", activity) : 0)); #endif
} else
ereport(lev,
/*------ translator:%sisanounphrasedescribingachildprocess,suchas
"server process" */
(errmsg("%s (PID %d) exited with unrecognized status %d",
procname, pid, exitstatus),
activity ? errdetail("Failed process was running: %s", activity) : 0));
}
/* *Advancethepostmaster'sstatemachineandtakeactionsasappropriate * *Thisiscommoncodeforprocess_pm_shutdown_request(), *process_pm_child_exit()andprocess_pm_pmsignal(),whichprocessthesignals *thatmightmeanweneedtochangestate.
*/ staticvoid
PostmasterStateMachine(void)
{ /* If we're doing a smart shutdown, try to advance that state. */ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{ if (!connsAllowed)
{ /* *Thisstateendswhenwehavenonormalclientbackendsrunning. *Thenwe'rereadytostopotherchildren.
*/ if (CountChildren(btmask(B_BACKEND)) == 0)
UpdatePMState(PM_STOP_BACKENDS);
}
}
/* these are not real postmaster children */
remainMask = btmask_add(remainMask,
B_INVALID,
B_STANDALONE_BACKEND);
/* All types should be included in targetMask or remainMask */
Assert((remainMask.mask | targetMask.mask) == BTYPE_MASK_ALL.mask);
} #endif
/* If we had not yet signaled the processes to exit, do so now */ if (pmState == PM_STOP_BACKENDS)
{ /* *Forgetanypendingrequestsforbackgroundworkers,sincewe're *nolongerwillingtolaunchanynewworkers.(Ifadditional *requestsarrive,BackgroundWorkerStateChangewillrejectthem.)
*/
ForgetUnstartedBackgroundWorkers();
SignalChildren(SIGTERM, targetMask);
UpdatePMState(PM_WAIT_BACKENDS);
}
/* Are any of the target processes still running? */ if (CountChildren(targetMask) == 0)
{ if (Shutdown >= ImmediateShutdown || FatalError)
{ /* *Stopanydead-endchildrenandstopcreatingnewones. * *NB:SimilarcodeexistsinHandleFatalError(),whenthe *errorhappensinpmState>PM_WAIT_BACKENDS.
*/
UpdatePMState(PM_WAIT_DEAD_END);
ConfigurePostmasterWaitSet(false);
SignalChildren(SIGQUIT, btmask(B_DEAD_END_BACKEND));
/* *WealreadySIGQUIT'dauxiliaryprocesses(otherthan *logger),ifany,whenwestartedimmediateshutdownor *enteredFatalErrorstate.
*/
} else
{ /* *Ifwegethere,weareproceedingwithnormalshutdown.All *theregularchildrenaregone,andit'stimetotellthe *checkpointertodoashutdowncheckpoint.
*/
Assert(Shutdown > NoShutdown); /* Start the checkpointer if not running */ if (CheckpointerPMChild == NULL)
CheckpointerPMChild = StartChildProcess(B_CHECKPOINTER); /* And tell it to write the shutdown checkpoint */ if (CheckpointerPMChild != NULL)
{
signal_child(CheckpointerPMChild, SIGINT);
UpdatePMState(PM_WAIT_XLOG_SHUTDOWN);
} else
{ /* *Ifwefailedtoforkacheckpointer,justshutdown. *Anyrequiredcleanupwillhappenatnextrestart.We *setFatalErrorsothatan"abnormalshutdown"message *getsloggedwhenweexit. * *Wedon'tconsultsend_abort_for_crashhere,asit's *unlikelythatdumpingcoreswouldilluminatethereason *forcheckpointerforkfailure. * *XXX:ItmaybeworthtointroduceadifferentPMQUIT *valuethatsignalsthattheclusterisinabadstate, *withoutaprocesshavingcrashed.Butrightnowthis *pathisveryunlikelytobereached,soitisn't *obviouslyworthwhileaddingadistincterrormessagein *quickdie().
*/
HandleFatalError(PMQUIT_FOR_CRASH, false);
}
}
}
}
/* *Ifthestartupprocessfailed,ortheuserdoesnotwantanautomatic *restartafterbackendcrashes,waitforallnon-sysloggerchildrento *exit,andthenexitpostmaster.Wedon'ttrytoreinitializewhenthe *startupprocessfails,becausemorethanlikelyitwilljustfailagain *andwewillkeeptryingforever.
*/ if (pmState == PM_NO_CHILDREN)
{ if (StartupStatus == STARTUP_CRASHED)
{
ereport(LOG,
(errmsg("shutting down due to startup process failure")));
ExitPostmaster(1);
} if (!restart_after_crash)
{
ereport(LOG,
(errmsg("shutting down because \"restart_after_crash\" is off")));
ExitPostmaster(1);
}
}
/* *Ifweneedtorecoverfromacrash,waitforallnon-sysloggerchildren *toexit,thenresetshmemandstartthestartupprocess.
*/ if (FatalError && pmState == PM_NO_CHILDREN)
{
ereport(LOG,
(errmsg("all server processes terminated; reinitializing")));
/* remove leftover temporary files after a crash */ if (remove_temp_files_after_crash)
RemovePgTempFiles();
/* allow background workers to immediately restart */
ResetBackgroundWorkerCrashTimes();
shmem_exit(1);
/* re-read control file into local memory */
LocalProcessControlFile(true);
/* re-create shared memory and semaphores */
CreateSharedMemoryAndSemaphores();
UpdatePMState(PM_STARTUP);
/* Make sure we can perform I/O while starting up. */
maybe_adjust_io_workers();
/* *Launchbackgroundprocessesafterstatechange,orrelaunchafteran *existingprocesshasexited. * *CheckthecurrentpmStateandthestatusofanybackgroundprocesses.If *thereareanybackgroundprocessesmissingthatshouldberunninginthe *currentstate,butarenot,launchthem.
*/ staticvoid
LaunchMissingBackgroundProcesses(void)
{ /* Syslogger is active in all states */ if (SysLoggerPMChild == NULL && Logging_collector)
StartSysLogger();
/* *IfweneedtostartaWALreceiver,trytodothatnow * *Note:ifawalreceiverprocessisalreadyrunning,itmightseemthat *weshouldclearWalReceiverRequested.However,there'sarace *conditionifthewalreceiverterminatesandthestartupprocess *immediatelyrequestsanewone:it'squitepossibletogetthesignal *fortherequestbeforereapingthedeadwalreceiverprocess.Betterto *risklaunchinganextrawalreceiverthantomisslaunchingoneweneed. *(Thewalreceivercodehaslogictorecognizethatitshouldgoawayif *notneeded.)
*/ if (WalReceiverRequested)
{ if (WalReceiverPMChild == NULL &&
(pmState == PM_STARTUP || pmState == PM_RECOVERY ||
pmState == PM_HOT_STANDBY) &&
Shutdown <= SmartShutdown)
{
WalReceiverPMChild = StartChildProcess(B_WAL_RECEIVER); if (WalReceiverPMChild != 0)
WalReceiverRequested = false; /* else leave the flag set, so we'll try again later */
}
}
/* If we need to start a WAL summarizer, try to do that now */ if (summarize_wal && WalSummarizerPMChild == NULL &&
(pmState == PM_RUN || pmState == PM_HOT_STANDBY) &&
Shutdown <= SmartShutdown)
WalSummarizerPMChild = StartChildProcess(B_WAL_SUMMARIZER);
/* Get other worker processes running, if needed */ if (StartWorkerNeeded || HaveCrashedWorker)
maybe_start_bgworkers();
}
/* *Returnstringrepresentationofsignal. * *Becausethisisonlyimplementedforsignalswealreadyrelyoninthis *filewedon'tneedtodealwithunimplementedorsame-numeric-valuesignals *(aswe'de.g.havetoforEWOULDBLOCK/EAGAIN).
*/ staticconstchar *
pm_signame(int signal)
{ #define PM_TOSTR_CASE(sym) case sym: return#sym switch (signal)
{
PM_TOSTR_CASE(SIGABRT);
PM_TOSTR_CASE(SIGCHLD);
PM_TOSTR_CASE(SIGHUP);
PM_TOSTR_CASE(SIGINT);
PM_TOSTR_CASE(SIGKILL);
PM_TOSTR_CASE(SIGQUIT);
PM_TOSTR_CASE(SIGTERM);
PM_TOSTR_CASE(SIGUSR1);
PM_TOSTR_CASE(SIGUSR2); default: /* all signals sent by postmaster should be listed here */
Assert(false); return"(unknown)";
} #undef PM_TOSTR_CASE
ereport(DEBUG3,
(errmsg_internal("sending signal %d/%s to %s process with pid %d",
signal, pm_signame(signal),
GetBackendTypeDesc(pmchild->bkend_type),
(int) pmchild->pid)));
if (kill(pid, signal) < 0)
elog(DEBUG3, "kill(%ld,%d) failed: %m", (long) pid, signal); #ifdef HAVE_SETSID switch (signal)
{ case SIGINT: case SIGTERM: case SIGQUIT: case SIGKILL: case SIGABRT: if (kill(-pid, signal) < 0)
elog(DEBUG3, "kill(%ld,%d) failed: %m", (long) (-pid), signal); break; default: break;
} #endif
}
/* *Allocateandassignthechildslot.Notewemustdothisbefore *forking,sothatwecanhandlefailures(outofmemoryorchild-process *slots)cleanly.
*/
cac = canAcceptConnections(B_BACKEND); if (cac == CAC_OK)
{ /* Can change later to B_WAL_SENDER */
bn = AssignPostmasterChildSlot(B_BACKEND); if (!bn)
{ /* *Toomanyregularchildprocesses;launchadead-endchild *processinstead.
*/
cac = CAC_TOOMANY;
}
} if (!bn)
{
bn = AllocDeadEndChild(); if (!bn)
{
ereport(LOG,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); return STATUS_ERROR;
}
}
/* Pass down canAcceptConnections state */
startup_data.canAcceptConnections = cac;
bn->rw = NULL;
/* Hasn't asked to be notified about any bgworkers yet */
bn->bgworker_notify = false;
pid = postmaster_child_launch(bn->bkend_type, bn->child_slot,
&startup_data, sizeof(startup_data),
client_sock); if (pid < 0)
{ /* in parent, fork failed */ int save_errno = errno;
(void) ReleasePostmasterChildSlot(bn);
errno = save_errno;
ereport(LOG,
(errmsg("could not fork new process for connection: %m")));
report_fork_failure_to_client(client_sock, save_errno); return STATUS_ERROR;
}
/* in parent, successful fork */
ereport(DEBUG2,
(errmsg_internal("forked new %s, pid=%d socket=%d",
GetBackendTypeDesc(bn->bkend_type),
(int) pid, (int) client_sock->sock)));
/* *Trytoreportbackendfork()failuretoclientbeforeweclosethe *connection.Sincewedonotcaretoriskblockingthepostmasteron *thisconnection,wesettheconnectiontonon-blockingandtryonlyonce. * *Thisisgrungyspecial-purposecode;wecannotusebackendlibpqsince *it'snotupandrunning.
*/ staticvoid
report_fork_failure_to_client(ClientSocket *client_sock, int errnum)
{ char buffer[1000]; int rc;
/* Format the error message packet (always V2 protocol) */
snprintf(buffer, sizeof(buffer), "E%s%s\n",
_("could not fork new process for connection: "),
strerror(errnum));
/* Set port to non-blocking. Don't do send() if this fails */ if (!pg_set_noblock(client_sock->sock)) return;
/* We'll retry after EINTR, but ignore all other failures */ do
{
rc = send(client_sock->sock, buffer, strlen(buffer) + 1, 0);
} while (rc < 0 && errno == EINTR);
}
if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) &&
(pmState == PM_RECOVERY && Shutdown == NoShutdown))
{
ereport(LOG,
(errmsg("database system is ready to accept read-only connections")));
/* Some workers may be scheduled to start now */
StartWorkerNeeded = true;
}
/* Process background worker state changes. */ if (CheckPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE))
{ /* Accept new worker requests only if not stopping. */
BackgroundWorkerStateChange(pmState < PM_STOP_BACKENDS);
StartWorkerNeeded = true;
}
/* Tell syslogger to rotate logfile if requested */ if (SysLoggerPMChild != NULL)
{ if (CheckLogrotateSignal())
{
signal_child(SysLoggerPMChild, SIGUSR1);
RemoveLogrotateSignalFiles();
} elseif (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE))
{
signal_child(SysLoggerPMChild, SIGUSR1);
}
}
if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER) &&
Shutdown <= SmartShutdown && pmState < PM_STOP_BACKENDS)
{ /* The autovacuum launcher wants us to start a worker process. */
StartAutovacuumWorker();
}
if (CheckPostmasterSignal(PMSIGNAL_START_WALRECEIVER))
{ /* Startup Process wants us to start the walreceiver process. */
WalReceiverRequested = true;
}
if (CheckPostmasterSignal(PMSIGNAL_XLOG_IS_SHUTDOWN))
{ /* Checkpointer completed the shutdown checkpoint */ if (pmState == PM_WAIT_XLOG_SHUTDOWN)
{ /* *Ifwehaveanarchiversubprocess,tellittodoalastarchive *cycleandquit.Likewise,ifwehavewalsenderprocesses,tell *themtosendanyremainingWALandquit.
*/
Assert(Shutdown > NoShutdown);
/* Waken archiver for the last time */ if (PgArchPMChild != NULL)
signal_child(PgArchPMChild, SIGUSR2);
pmchild = AssignPostmasterChildSlot(type); if (!pmchild)
{ if (type == B_AUTOVAC_WORKER)
ereport(LOG,
(errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
errmsg("no slot available for new autovacuum worker process"))); else
{ /* shouldn't happen because we allocate enough slots */
elog(LOG, "no postmaster child slot available for aux process");
} return NULL;
}
pid = postmaster_child_launch(type, pmchild->child_slot, NULL, 0, NULL); if (pid < 0)
{ /* in parent, fork failed */
ReleasePostmasterChildSlot(pmchild);
ereport(LOG,
(errmsg("could not fork \"%s\" process: %m", PostmasterChildName(type))));
/* *Doesthecurrentpostmasterstaterequirestartingaworkerwiththe *specifiedstart_time?
*/ staticbool
bgworker_should_start_now(BgWorkerStartTime start_time)
{ switch (pmState)
{ case PM_NO_CHILDREN: case PM_WAIT_CHECKPOINTER: case PM_WAIT_DEAD_END: case PM_WAIT_XLOG_ARCHIVAL: case PM_WAIT_XLOG_SHUTDOWN: case PM_WAIT_IO_WORKERS: case PM_WAIT_BACKENDS: case PM_STOP_BACKENDS: break;
case PM_RUN: if (start_time == BgWorkerStart_RecoveryFinished) returntrue; /* fall through */
case PM_HOT_STANDBY: if (start_time == BgWorkerStart_ConsistentState) returntrue; /* fall through */
case PM_RECOVERY: case PM_STARTUP: case PM_INIT: if (start_time == BgWorkerStart_PostmasterStart) returntrue; /* fall through */
}
/* ignore if already running */ if (rw->rw_pid != 0) continue;
/* if marked for death, clean up and remove from list */ if (rw->rw_terminate)
{
ForgetBackgroundWorker(rw); continue;
}
/* *Ifthisworkerhascrashedpreviously,maybeitneedstobe *restarted(unlessonregistrationitspecifieditdoesn'twantto *berestartedatall).Checkhowlongagodidacrashlasthappen. *Ifthelastcrashistoorecent,don'tstartitrightaway;letit *berestartedonceenoughtimehaspassed.
*/ if (rw->rw_crashed_at != 0)
{ if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART)
{ int notify_pid;
notify_pid = rw->rw_worker.bgw_notify_pid;
ForgetBackgroundWorker(rw);
/* Report worker is gone now. */ if (notify_pid != 0)
kill(notify_pid, SIGUSR1);
continue;
}
/* read system time only when needed */ if (now == 0)
now = GetCurrentTimestamp();
if (!TimestampDifferenceExceeds(rw->rw_crashed_at, now,
rw->rw_worker.bgw_restart_time * 1000))
{ /* Set flag to remember that we have workers to start later */
HaveCrashedWorker = true; continue;
}
}
if (bgworker_should_start_now(rw->rw_worker.bgw_start_time))
{ /* reset crash time before trying to start worker */
rw->rw_crashed_at = 0;
/* Not enough running? */ while (io_worker_count < io_workers)
{
PMChild *child; int i;
/* find unused entry in io_worker_children array */ for (i = 0; i < MAX_IO_WORKERS; ++i)
{ if (io_worker_children[i] == NULL) break;
} if (i == MAX_IO_WORKERS)
elog(ERROR, "could not find a free IO worker slot");
/* Try to launch one. */
child = StartChildProcess(B_IO_WORKER); if (child != NULL)
{
io_worker_children[i] = child;
++io_worker_count;
} else break; /* try again next time */
}
/* Too many running? */ if (io_worker_count > io_workers)
{ /* ask the IO worker in the highest slot to exit */ for (int i = MAX_IO_WORKERS - 1; i >= 0; --i)
{ if (io_worker_children[i] != NULL)
{
kill(io_worker_children[i]->pid, SIGUSR2); break;
}
}
}
}
/* Try to consume one win32_deadchild_waitinfo from the queue. */ if (!GetQueuedCompletionStatus(win32ChildQueue, &dwd, &key, &ovl, 0))
{
errno = EAGAIN; return -1;
}
/* *Note!Codebelowexecutesonathreadpool!Alloperationsmust *bethreadsafe!Notethatelog()andfriendsmust*not*beused.
*/ staticvoid WINAPI
pgwin32_deadchild_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{ /* Should never happen, since we use INFINITE as timeout value. */ if (TimerOrWaitFired) return;
/* *Postthewin32_deadchild_waitinfoobjectforwaitpid()todealwith.If *thatfails,weleaktheobject,butwealsoleakawholeprocessand *getintoanunrecoverablestate,sothere'snotmuchpointinworrying *aboutthat.We'dliketopanic,butwecan'tusethatinfrastructure *fromthisthread.
*/ if (!PostQueuedCompletionStatus(win32ChildQueue, 0,
(ULONG_PTR) lpParameter,
NULL))
write_stderr("could not post child completion status\n");
/* *Createapipe.Postmasterholdsthewriteendofthepipeopen *(POSTMASTER_FD_OWN),andchildrenholdthereadend.Childrencanpass *thereadfiledescriptortoselect()towakeupincasepostmaster *dies,orcheckforpostmasterdeathwitha(read()==0).Childrenmust *closethewriteendassoonaspossibleafterforking,becauseEOF *won'tbesignaledinthereadenduntilallprocesseshaveclosedthe *writefd.ThatistakencareofinClosePostmasterPorts().
*/
Assert(MyProcPid == PostmasterPid); if (pipe(postmaster_alive_fds) < 0)
ereport(FATAL,
(errcode_for_file_access(),
errmsg_internal("could not create pipe to monitor postmaster death: %m")));
/* Notify fd.c that we've eaten two FDs for the pipe. */
ReserveExternalFD();
ReserveExternalFD();
/* *SetO_NONBLOCKtoallowtestingforthefd'spresencewitharead() *call.
*/ if (fcntl(postmaster_alive_fds[POSTMASTER_FD_WATCH], F_SETFL, O_NONBLOCK) == -1)
ereport(FATAL,
(errcode_for_socket_access(),
errmsg_internal("could not set postmaster death monitoring pipe to nonblocking mode: %m"))); #else
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.219Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.