diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c index f8ca52e..e84e2fc 100644 --- a/src/backend/port/win32_shmem.c +++ b/src/backend/port/win32_shmem.c @@ -382,6 +382,7 @@ PGSharedMemoryReAttach(void) Assert(UsedShmemSegAddr != NULL); Assert(IsUnderPostmaster); + /* FIXME change FATAL to proc_exit(1) */ /* * Release memory region reservation that was made by the postmaster diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index a4b53b3..eadf7f1 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -180,6 +180,14 @@ typedef struct bkend bool dead_end; /* is it going to send an error and quit? */ bool bgworker_notify; /* gets bgworker start/stop notifications */ dlist_node elem; /* list link in BackendList */ + +#ifdef EXEC_BACKEND +#define RETRYABLE_FORK +#endif +#ifdef RETRYABLE_FORK + Port *port; /* for still-opening backends */ + int retry_count; +#endif } Backend; static dlist_head BackendList = DLIST_STATIC_INIT(BackendList); @@ -412,6 +420,7 @@ static void BackendInitialize(Port *port); static void BackendRun(Port *port) pg_attribute_noreturn(); static void ExitPostmaster(int status) pg_attribute_noreturn(); static int ServerLoop(void); +static pid_t BackendFork(Backend *bn); static int BackendStartup(Port *port); static int ProcessStartupPacket(Port *port, bool SSLdone); static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options); @@ -427,6 +436,7 @@ static void TerminateChildren(int signal); #define SignalChildren(sig) SignalSomeChildren(sig, BACKEND_TYPE_ALL) static int CountChildren(int target); +static pid_t do_fork_bgworker(RegisteredBgWorker *rw); static bool assign_backendlist_entry(RegisteredBgWorker *rw); static void maybe_start_bgworkers(void); static bool CreateOptsFile(int argc, char *argv[], char *fullprogname); @@ -543,6 +553,7 @@ static bool save_backend_variables(BackendParameters *param, Port *port, #endif static void ShmemBackendArrayAdd(Backend *bn); +static void ShmemBackendArrayUpdate(Backend *bn, pid_t oldpid); static void ShmemBackendArrayRemove(Backend *bn); #endif /* EXEC_BACKEND */ @@ -556,6 +567,7 @@ static void ShmemBackendArrayRemove(Backend *bn); #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) +#define EXIT_STATUS_4(st) (WIFEXITED(st) && WEXITSTATUS(st) == 4) #ifndef WIN32 /* @@ -1703,14 +1715,8 @@ ServerLoop(void) port = ConnCreate(ListenSocket[i]); if (port) { + /* FIXME refactor more to happen in BackendStartup() */ BackendStartup(port); - - /* - * We no longer need the open socket or port structure - * in this process - */ - StreamClose(port->sock); - ConnFree(port); } } } @@ -2311,7 +2317,11 @@ processCancelRequest(Port *port, void *pkt) backendPID))); return; } +#ifndef EXEC_BACKEND + } +#else } +#endif /* No matching backend */ ereport(LOG, @@ -2393,8 +2403,6 @@ ConnCreate(int serverFd) if (StreamConnection(serverFd, port) != STATUS_OK) { - if (port->sock != PGINVALID_SOCKET) - StreamClose(port->sock); ConnFree(port); return NULL; } @@ -2425,6 +2433,8 @@ ConnCreate(int serverFd) static void ConnFree(Port *conn) { + if (conn->sock != PGINVALID_SOCKET) + StreamClose(conn->sock); #ifdef USE_SSL secure_close(conn); #endif @@ -2814,6 +2824,8 @@ reaper(SIGNAL_ARGS) continue; } + /* FIXME restart startup process after status 4 */ + /* * Unexpected exit of startup process (including FATAL exit) * during PM_STARTUP is treated as catastrophic. There are no @@ -2897,14 +2909,15 @@ reaper(SIGNAL_ARGS) } /* - * Was it the bgwriter? Normal exit can be ignored; we'll start a new - * one at the next iteration of the postmaster's main loop, if - * necessary. Any other exit condition is treated as a crash. + * Was it the bgwriter? Normal exit and retryable startup failure can + * be ignored; we'll start a new one at the next iteration of the + * postmaster's main loop, if necessary. Any other exit condition is + * treated as a crash. */ if (pid == BgWriterPID) { BgWriterPID = 0; - if (!EXIT_STATUS_0(exitstatus)) + if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_4(exitstatus)) HandleChildCrash(pid, exitstatus, _("background writer process")); continue; @@ -2953,6 +2966,7 @@ reaper(SIGNAL_ARGS) if (PgStatPID != 0) signal_child(PgStatPID, SIGQUIT); } + /* FIXME retry checkpointer */ else { /* @@ -2967,44 +2981,47 @@ reaper(SIGNAL_ARGS) } /* - * Was it the wal writer? Normal exit can be ignored; we'll start a - * new one at the next iteration of the postmaster's main loop, if - * necessary. Any other exit condition is treated as a crash. + * Was it the wal writer? Normal exit and retryable startup failure + * can be ignored; we'll start a new one at the next iteration of the + * postmaster's main loop, if necessary. Any other exit condition is + * treated as a crash. */ if (pid == WalWriterPID) { WalWriterPID = 0; - if (!EXIT_STATUS_0(exitstatus)) + if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_4(exitstatus)) HandleChildCrash(pid, exitstatus, _("WAL writer process")); continue; } /* - * Was it the wal receiver? If exit status is zero (normal) or one - * (FATAL exit), we assume everything is all right just like normal - * backends. (If we need a new wal receiver, we'll start one at the - * next iteration of the postmaster's main loop.) + * Was it the wal receiver? If exit status is zero (normal), one + * (FATAL exit) or four (retryable startup failure), we assume + * everything is all right just like normal backends. (If we need a + * new wal receiver, we'll start one at the next iteration of the + * postmaster's main loop.) */ if (pid == WalReceiverPID) { WalReceiverPID = 0; - if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus)) + if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus) && + !EXIT_STATUS_4(exitstatus)) HandleChildCrash(pid, exitstatus, _("WAL receiver process")); continue; } /* - * Was it the autovacuum launcher? Normal exit can be ignored; we'll - * start a new one at the next iteration of the postmaster's main - * loop, if necessary. Any other exit condition is treated as a - * crash. + * Was it the autovacuum launcher? Normal exit and retryable startup + * failure can be ignored; we'll start a new one at the next iteration + * of the postmaster's main loop, if necessary. Any other exit + * condition is treated as a crash. */ if (pid == AutoVacPID) { AutoVacPID = 0; - if (!EXIT_STATUS_0(exitstatus)) + if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_4(exitstatus)) HandleChildCrash(pid, exitstatus, _("autovacuum launcher process")); continue; @@ -3116,33 +3133,60 @@ CleanupBackgroundWorker(int pid, snprintf(namebuf, MAXPGPATH, _("background worker \"%s\""), rw->rw_worker.bgw_type); + LogChildExit(DEBUG2, namebuf, pid, exitstatus); - if (!EXIT_STATUS_0(exitstatus)) - { - /* Record timestamp, so we know when to restart the worker. */ - rw->rw_crashed_at = GetCurrentTimestamp(); - } - else + if (EXIT_STATUS_0(exitstatus)) { /* Zero exit status means terminate */ rw->rw_crashed_at = 0; rw->rw_terminate = true; } + else if (!EXIT_STATUS_4(exitstatus)) + { + /* Record timestamp, so we know when to restart the worker. */ + rw->rw_crashed_at = GetCurrentTimestamp(); + } /* * Additionally, for shared-memory-connected workers, just like a - * backend, any exit status other than 0 or 1 is considered a crash + * backend, any exit status other than 0, 1 or 4 is considered a crash * and causes a system-wide restart. */ if ((rw->rw_worker.bgw_flags & BGWORKER_SHMEM_ACCESS) != 0) { - if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus)) + if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus) && + !EXIT_STATUS_4(exitstatus)) { HandleChildCrash(pid, exitstatus, namebuf); return true; } } +#ifdef RETRYABLE_FORK + if (EXIT_STATUS_4(exitstatus)) + { + Backend *bp = rw->rw_backend; + + if (++bp->retry_count >= 100) /* FIXME use a constant */ + { + ereport(LOG, + (errmsg("giving up after too many tries to reserve shared memory"), + errhint("This might be caused by ASLR or antivirus software."))); + } + else + { + bp->pid = do_fork_bgworker(rw); + if (bp->pid > 0) + { + ShmemBackendArrayUpdate(bp, pid); + return true; + } + } + /* mark entry as crashed, so we'll try again later */ + rw->rw_crashed_at = GetCurrentTimestamp(); + } +#endif + /* * We must release the postmaster child slot whether this worker is * connected to shared memory or not, but we only treat it as a crash @@ -3187,7 +3231,8 @@ CleanupBackgroundWorker(int pid, /* * CleanupBackend -- cleanup after terminated backend. * - * Remove all local state associated with backend. + * If the backend failed during early startup, retry forking it. Otherwise, + * remove all local state associated with backend. * * If you change this, see also CleanupBackgroundWorker. */ @@ -3222,7 +3267,8 @@ CleanupBackend(int pid, } #endif - if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus)) + if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus) && + !EXIT_STATUS_4(exitstatus)) { HandleChildCrash(pid, exitstatus, _("server process")); return; @@ -3234,6 +3280,40 @@ CleanupBackend(int pid, if (bp->pid == pid) { +#ifdef RETRYABLE_FORK + if (EXIT_STATUS_4(exitstatus)) + { + Assert(bp->port); + + if (++bp->retry_count >= 100) + { + ereport(LOG, + (errmsg("giving up after too many tries to reserve shared memory"), + errhint("This might be caused by ASLR or antivirus software."))); + report_fork_failure_to_client(bp->port, EAGAIN); + } + else + { + bp->pid = BackendFork(bp); + if (bp->pid > 0) + { + if (!bp->dead_end) + ShmemBackendArrayUpdate(bp, pid); + return; + } + /* Else, fork failed. Fall through to remove local state. */ + } + } + /* + * For a sufficiently long-running backend, FIXME will have + * already called ConnFree(). + */ + if (bp->port) + { + ConnFree(bp->port); + bp->port = NULL; + } +#endif if (!bp->dead_end) { if (!ReleasePostmasterChildSlot(bp->child_slot)) @@ -3607,6 +3687,14 @@ LogChildExit(int lev, const char *procname, int pid, int exitstatus) static void PostmasterStateMachine(void) { + if (pmState == PM_STARTUP && StartupStatus == STARTUP_NOT_RUNNING) + { + /* We need a startup process, either the */ + StartupPID = StartupDataBase(); + Assert(StartupPID != 0); + StartupStatus = STARTUP_RUNNING; + } + if (pmState == PM_WAIT_BACKUP) { /* @@ -3954,9 +4042,60 @@ TerminateChildren(int signal) signal_child(PgStatPID, signal); } +/* FIXME comment */ +static pid_t +BackendFork(Backend *bn) +{ + pid_t pid; + + MyCancelKey = bn->cancel_key; + MyPMChildSlot = bn->child_slot; + +#ifdef EXEC_BACKEND + pid = backend_forkexec(bn->port); +#else /* !EXEC_BACKEND */ + pid = fork_process(); + if (pid == 0) /* child */ + { + /* Detangle from postmaster */ + InitPostmasterChild(); + + /* Close the postmaster's sockets */ + ClosePostmasterPorts(false); + + /* Perform additional initialization and collect startup packet */ + BackendInitialize(bn->port); + + /* And run the backend */ + BackendRun(bn->port); + } +#endif /* EXEC_BACKEND */ + + if (pid < 0) + { + /* in parent, fork failed */ + int save_errno = errno; + + errno = save_errno; + ereport(LOG, + (errmsg("could not fork new process for connection: %m"))); + report_fork_failure_to_client(bn->port, save_errno); + } + else + { + /* in parent, successful fork */ + ereport(DEBUG2, + (errmsg_internal("forked new backend, pid=%d socket=%d", + (int) pid, (int) bn->port->sock))); + } + + return pid; +} + /* * BackendStartup -- start backend process * + * FIXME * returns: STATUS_ERROR if the fork failed, STATUS_OK otherwise. * * Note: if you change this code, also consider StartAutovacuumWorker. @@ -3965,7 +4104,6 @@ static int BackendStartup(Port *port) { Backend *bn; /* for backend cleanup */ - pid_t pid; /* * Create backend data structure. Better before the fork() so we can @@ -3977,24 +4115,13 @@ BackendStartup(Port *port) ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); - return STATUS_ERROR; - } - - /* - * Compute the cancel key that will be assigned to this backend. The - * backend will have its own copy in the forked-off process' value of - * MyCancelKey, so that it can transmit the key to the frontend. - */ - if (!RandomCancelKey(&MyCancelKey)) - { - free(bn); - ereport(LOG, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("could not generate random cancel key"))); - return STATUS_ERROR; + goto err; } - bn->cancel_key = MyCancelKey; +#ifdef RETRYABLE_FORK + bn->port = port; + bn->retry_count = 0; +#endif /* Pass down canAcceptConnections state */ port->canAcceptConnections = canAcceptConnections(); @@ -4005,60 +4132,38 @@ BackendStartup(Port *port) * Unless it's a dead_end child, assign it a child slot number */ if (!bn->dead_end) - bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); + bn->child_slot = AssignPostmasterChildSlot(); else bn->child_slot = 0; /* Hasn't asked to be notified about any bgworkers yet */ bn->bgworker_notify = false; -#ifdef EXEC_BACKEND - pid = backend_forkexec(port); -#else /* !EXEC_BACKEND */ - pid = fork_process(); - if (pid == 0) /* child */ + /* Compute the cancel key that will be assigned to this backend. */ + if (!RandomCancelKey(&bn->cancel_key)) { - free(bn); - - /* Detangle from postmaster */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - /* Perform additional initialization and collect startup packet */ - BackendInitialize(port); - - /* And run the backend */ - BackendRun(port); - } -#endif /* EXEC_BACKEND */ - - if (pid < 0) - { - /* in parent, fork failed */ - int save_errno = errno; - - if (!bn->dead_end) - (void) ReleasePostmasterChildSlot(bn->child_slot); - free(bn); - errno = save_errno; ereport(LOG, - (errmsg("could not fork new process for connection: %m"))); - report_fork_failure_to_client(port, save_errno); - return STATUS_ERROR; + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not generate random cancel key"))); + goto err; } - /* in parent, successful fork */ - ereport(DEBUG2, - (errmsg_internal("forked new backend, pid=%d socket=%d", - (int) pid, (int) port->sock))); + bn->pid = BackendFork(bn); + if (bn->pid < 0) + goto err; + +#ifndef RETRYABLE_FORK + /* + * We no longer need the open socket or port structure + * in this process + */ + ConnFree(port); +#endif /* * Everything's been successful, it's safe to add this backend to our list * of backends. */ - bn->pid = pid; bn->bkend_type = BACKEND_TYPE_NORMAL; /* Can change later to WALSND */ dlist_push_head(&BackendList, &bn->elem); @@ -4068,6 +4173,16 @@ BackendStartup(Port *port) #endif return STATUS_OK; + +err: + ConnFree(port); + if (bn) + { + if (bn->child_slot) + (void) ReleasePostmasterChildSlot(bn->child_slot); + free(bn); + } + return STATUS_ERROR; } /* @@ -4708,6 +4823,15 @@ retry: #endif /* WIN32 */ +static void +MarkSharedStateComplete(void) +{ +#ifdef FIXME_WIN32 + SendPostmasterSignal(PMSIGNAL_BACKEND_SHMAT); +#endif +} + + /* * SubPostmasterMain -- Get the fork/exec'd process into a state equivalent * to what it would be if we'd simply forked on Unix, and then @@ -4783,7 +4907,24 @@ SubPostmasterMain(int argc, char *argv[]) strcmp(argv[1], "--forkavworker") == 0 || strcmp(argv[1], "--forkboot") == 0 || strncmp(argv[1], "--forkbgworker=", 15) == 0) + { + /* test retryable starts */ + if (0 && (strcmp(argv[1], "--forkbackend") == 0 || + strcmp(argv[1], "--forkavlauncher") == 0 || + strcmp(argv[1], "--forkavworker") == 0 || + /* strcmp(argv[1], "--forkboot") == 0 || */ + strncmp(argv[1], "--forkbgworker=", 15) == 0)) + { + MyProcPid = getpid(); /* FIXME not needed? */ + srandom((unsigned int ) (MyProcPid ^ MyStartTime)); + if (random() % 10 != 0) + { + elog(LOG, "failing startup for testing purposes"); + proc_exit(4); + } + } PGSharedMemoryReAttach(); + } else PGSharedMemoryNoReAttach(); @@ -4878,6 +5019,7 @@ SubPostmasterMain(int argc, char *argv[]) /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(false, 0); + MarkSharedStateComplete(); /* And run the backend */ BackendRun(&port); /* does not return */ @@ -4892,6 +5034,7 @@ SubPostmasterMain(int argc, char *argv[]) /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(false, 0); + MarkSharedStateComplete(); AuxiliaryProcessMain(argc - 2, argv + 2); /* does not return */ } @@ -4905,6 +5048,7 @@ SubPostmasterMain(int argc, char *argv[]) /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(false, 0); + MarkSharedStateComplete(); AutoVacLauncherMain(argc - 2, argv + 2); /* does not return */ } @@ -4918,6 +5062,7 @@ SubPostmasterMain(int argc, char *argv[]) /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(false, 0); + MarkSharedStateComplete(); AutoVacWorkerMain(argc - 2, argv + 2); /* does not return */ } @@ -4936,6 +5081,7 @@ SubPostmasterMain(int argc, char *argv[]) /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(false, 0); + MarkSharedStateComplete(); /* Fetch MyBgworkerEntry from shared memory */ shmem_slot = atoi(argv[1] + 15); @@ -4952,12 +5098,14 @@ SubPostmasterMain(int argc, char *argv[]) if (strcmp(argv[1], "--forkcol") == 0) { /* Do not want to attach to shared memory */ + MarkSharedStateComplete(); PgstatCollectorMain(argc, argv); /* does not return */ } if (strcmp(argv[1], "--forklog") == 0) { /* Do not want to attach to shared memory */ + MarkSharedStateComplete(); SysLoggerMain(argc, argv); /* does not return */ } @@ -5620,40 +5768,14 @@ bgworker_forkexec(int shmem_slot) } #endif -/* - * Start a new bgworker. - * Starting time conditions must have been checked already. - * - * Returns true on success, false on failure. - * In either case, update the RegisteredBgWorker's state appropriately. - * - * This code is heavily based on autovacuum.c, q.v. - */ -static bool -do_start_bgworker(RegisteredBgWorker *rw) +/* FIXME comment */ +static pid_t +do_fork_bgworker(RegisteredBgWorker *rw) { pid_t worker_pid; - Assert(rw->rw_pid == 0); - - /* - * Allocate and assign the Backend element. Note we must do this before - * forking, so that we can handle out of memory properly. - * - * Treat failure as though the worker had crashed. That way, the - * postmaster will wait a bit before attempting to start it again; if it - * tried again right away, most likely it'd find itself repeating the - * out-of-memory or fork failure condition. - */ - if (!assign_backendlist_entry(rw)) - { - rw->rw_crashed_at = GetCurrentTimestamp(); - return false; - } - - ereport(DEBUG1, - (errmsg("starting background worker process \"%s\"", - rw->rw_worker.bgw_name))); + MyCancelKey = rw->rw_backend->cancel_key; + MyPMChildSlot = rw->rw_backend->child_slot; #ifdef EXEC_BACKEND switch ((worker_pid = bgworker_forkexec(rw->rw_shmem_slot))) @@ -5665,13 +5787,6 @@ do_start_bgworker(RegisteredBgWorker *rw) /* in postmaster, fork failed ... */ ereport(LOG, (errmsg("could not fork worker process: %m"))); - /* undo what assign_backendlist_entry did */ - ReleasePostmasterChildSlot(rw->rw_child_slot); - rw->rw_child_slot = 0; - free(rw->rw_backend); - rw->rw_backend = NULL; - /* mark entry as crashed, so we'll try again later */ - rw->rw_crashed_at = GetCurrentTimestamp(); break; #ifndef EXEC_BACKEND @@ -5702,15 +5817,73 @@ do_start_bgworker(RegisteredBgWorker *rw) #endif default: /* in postmaster, fork successful ... */ - rw->rw_pid = worker_pid; + rw->rw_pid = worker_pid; /* FIXME move later */ rw->rw_backend->pid = rw->rw_pid; - ReportBackgroundWorkerPID(rw); - /* add new worker to lists of backends */ - dlist_push_head(&BackendList, &rw->rw_backend->elem); + ReportBackgroundWorkerPID(rw); /* FIXME move later */ + + ereport(DEBUG2, + (errmsg_internal("FIXME forked new bgworker, pid=%d", + (int) worker_pid))); + } + + return worker_pid; +} + +/* + * Start a new bgworker. + * Starting time conditions must have been checked already. + * + * Returns true on success, false on failure. + * In either case, update the RegisteredBgWorker's state appropriately. + * FIXME responsible for BackendList lifecycle + * + * This code is heavily based on autovacuum.c, q.v. + */ +static bool +do_start_bgworker(RegisteredBgWorker *rw) +{ + pid_t worker_pid; + + Assert(rw->rw_pid == 0); + + /* + * Allocate and assign the Backend element. Note we must do this before + * forking, so that we can handle out of memory properly. + * + * Treat failure as though the worker had crashed. That way, the + * postmaster will wait a bit before attempting to start it again; if it + * tried again right away, most likely it'd find itself repeating the + * out-of-memory or fork failure condition. + */ + if (!assign_backendlist_entry(rw)) + { + rw->rw_crashed_at = GetCurrentTimestamp(); + return false; + } + + ereport(DEBUG1, + (errmsg("starting background worker process \"%s\"", + rw->rw_worker.bgw_name))); + + worker_pid = do_fork_bgworker(rw); + if (worker_pid == -1) + { + /* undo what assign_backendlist_entry did */ + ReleasePostmasterChildSlot(rw->rw_child_slot); + rw->rw_child_slot = 0; + free(rw->rw_backend); + rw->rw_backend = NULL; + /* mark entry as crashed, so we'll try again later */ + rw->rw_crashed_at = GetCurrentTimestamp(); + } + else + { + /* add new worker to lists of backends */ + dlist_push_head(&BackendList, &rw->rw_backend->elem); #ifdef EXEC_BACKEND - ShmemBackendArrayAdd(rw->rw_backend); + ShmemBackendArrayAdd(rw->rw_backend); #endif - return true; + return true; } return false; @@ -5797,6 +5970,10 @@ assign_backendlist_entry(RegisteredBgWorker *rw) bn->bkend_type = BACKEND_TYPE_BGWORKER; bn->dead_end = false; bn->bgworker_notify = false; +#ifdef RETRYABLE_FORK + bn->port = NULL; + bn->retry_count = 0; +#endif rw->rw_backend = bn; rw->rw_child_slot = bn->child_slot; @@ -6306,6 +6483,15 @@ ShmemBackendArrayAdd(Backend *bn) } static void +ShmemBackendArrayUpdate(Backend *bn, pid_t oldpid) +{ + int i = bn->child_slot - 1; + + Assert(ShmemBackendArray[i].pid == oldpid); + ShmemBackendArray[i] = *bn; +} + +static void ShmemBackendArrayRemove(Backend *bn) { int i = bn->child_slot - 1; diff --git a/src/include/storage/pmsignal.h b/src/include/storage/pmsignal.h index 0747341..1a6a46c 100644 --- a/src/include/storage/pmsignal.h +++ b/src/include/storage/pmsignal.h @@ -35,6 +35,7 @@ typedef enum PMSIGNAL_RECOVERY_STARTED, /* recovery has started */ PMSIGNAL_BEGIN_HOT_STANDBY, /* begin Hot Standby */ PMSIGNAL_WAKEN_ARCHIVER, /* send a NOTIFY signal to xlog archiver */ + PMSIGNAL_BACKEND_SHMAT, /* newest backend no longer seeks shmem attachment */ PMSIGNAL_ROTATE_LOGFILE, /* send SIGUSR1 to syslogger to rotate logfile */ PMSIGNAL_START_AUTOVAC_LAUNCHER, /* start an autovacuum launcher */ PMSIGNAL_START_AUTOVAC_WORKER, /* start an autovacuum worker */