Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * startup.c
4 : *
5 : * The Startup process initialises the server and performs any recovery
6 : * actions that have been specified. Notice that there is no "main loop"
7 : * since the Startup process ends as soon as initialisation is complete.
8 : * (in standby mode, one can think of the replay loop as a main loop,
9 : * though.)
10 : *
11 : *
12 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
13 : *
14 : *
15 : * IDENTIFICATION
16 : * src/backend/postmaster/startup.c
17 : *
18 : *-------------------------------------------------------------------------
19 : */
20 : #include "postgres.h"
21 :
22 : #include "access/xlog.h"
23 : #include "access/xlogrecovery.h"
24 : #include "access/xlogutils.h"
25 : #include "libpq/pqsignal.h"
26 : #include "miscadmin.h"
27 : #include "postmaster/auxprocess.h"
28 : #include "postmaster/startup.h"
29 : #include "storage/ipc.h"
30 : #include "storage/pmsignal.h"
31 : #include "storage/procsignal.h"
32 : #include "storage/standby.h"
33 : #include "utils/guc.h"
34 : #include "utils/memutils.h"
35 : #include "utils/timeout.h"
36 :
37 :
38 : #ifndef USE_POSTMASTER_DEATH_SIGNAL
39 : /*
40 : * On systems that need to make a system call to find out if the postmaster has
41 : * gone away, we'll do so only every Nth call to ProcessStartupProcInterrupts().
42 : * This only affects how long it takes us to detect the condition while we're
43 : * busy replaying WAL. Latch waits and similar which should react immediately
44 : * through the usual techniques.
45 : */
46 : #define POSTMASTER_POLL_RATE_LIMIT 1024
47 : #endif
48 :
49 : /*
50 : * Flags set by interrupt handlers for later service in the redo loop.
51 : */
52 : static volatile sig_atomic_t got_SIGHUP = false;
53 : static volatile sig_atomic_t shutdown_requested = false;
54 : static volatile sig_atomic_t promote_signaled = false;
55 :
56 : /*
57 : * Flag set when executing a restore command, to tell SIGTERM signal handler
58 : * that it's safe to just proc_exit.
59 : */
60 : static volatile sig_atomic_t in_restore_command = false;
61 :
62 : /*
63 : * Time at which the most recent startup operation started.
64 : */
65 : static TimestampTz startup_progress_phase_start_time;
66 :
67 : /*
68 : * Indicates whether the startup progress interval mentioned by the user is
69 : * elapsed or not. TRUE if timeout occurred, FALSE otherwise.
70 : */
71 : static volatile sig_atomic_t startup_progress_timer_expired = false;
72 :
73 : /*
74 : * Time between progress updates for long-running startup operations.
75 : */
76 : int log_startup_progress_interval = 10000; /* 10 sec */
77 :
78 : /* Signal handlers */
79 : static void StartupProcTriggerHandler(SIGNAL_ARGS);
80 : static void StartupProcSigHupHandler(SIGNAL_ARGS);
81 :
82 : /* Callbacks */
83 : static void StartupProcExit(int code, Datum arg);
84 :
85 :
86 : /* --------------------------------
87 : * signal handler routines
88 : * --------------------------------
89 : */
90 :
91 : /* SIGUSR2: set flag to finish recovery */
92 : static void
93 48 : StartupProcTriggerHandler(SIGNAL_ARGS)
94 : {
95 48 : promote_signaled = true;
96 48 : WakeupRecovery();
97 48 : }
98 :
99 : /* SIGHUP: set flag to re-read config file at next convenient time */
100 : static void
101 32 : StartupProcSigHupHandler(SIGNAL_ARGS)
102 : {
103 32 : got_SIGHUP = true;
104 32 : WakeupRecovery();
105 32 : }
106 :
107 : /* SIGTERM: set flag to abort redo and exit */
108 : static void
109 63 : StartupProcShutdownHandler(SIGNAL_ARGS)
110 : {
111 63 : if (in_restore_command)
112 1 : proc_exit(1);
113 : else
114 62 : shutdown_requested = true;
115 62 : WakeupRecovery();
116 62 : }
117 :
118 : /*
119 : * Re-read the config file.
120 : *
121 : * If one of the critical walreceiver options has changed, flag xlog.c
122 : * to restart it.
123 : */
124 : static void
125 32 : StartupRereadConfig(void)
126 : {
127 32 : char *conninfo = pstrdup(PrimaryConnInfo);
128 32 : char *slotname = pstrdup(PrimarySlotName);
129 32 : bool tempSlot = wal_receiver_create_temp_slot;
130 : bool conninfoChanged;
131 : bool slotnameChanged;
132 32 : bool tempSlotChanged = false;
133 :
134 32 : ProcessConfigFile(PGC_SIGHUP);
135 :
136 32 : conninfoChanged = strcmp(conninfo, PrimaryConnInfo) != 0;
137 32 : slotnameChanged = strcmp(slotname, PrimarySlotName) != 0;
138 :
139 : /*
140 : * wal_receiver_create_temp_slot is used only when we have no slot
141 : * configured. We do not need to track this change if it has no effect.
142 : */
143 32 : if (!slotnameChanged && strcmp(PrimarySlotName, "") == 0)
144 12 : tempSlotChanged = tempSlot != wal_receiver_create_temp_slot;
145 32 : pfree(conninfo);
146 32 : pfree(slotname);
147 :
148 32 : if (conninfoChanged || slotnameChanged || tempSlotChanged)
149 11 : StartupRequestWalReceiverRestart();
150 32 : }
151 :
152 : /* Process various signals that might be sent to the startup process */
153 : void
154 2878030 : ProcessStartupProcInterrupts(void)
155 : {
156 : #ifdef POSTMASTER_POLL_RATE_LIMIT
157 : static uint32 postmaster_poll_count = 0;
158 : #endif
159 :
160 : /*
161 : * Process any requests or signals received recently.
162 : */
163 2878030 : if (got_SIGHUP)
164 : {
165 32 : got_SIGHUP = false;
166 32 : StartupRereadConfig();
167 : }
168 :
169 : /*
170 : * Check if we were requested to exit without finishing recovery.
171 : */
172 2878030 : if (shutdown_requested)
173 57 : proc_exit(1);
174 :
175 : /*
176 : * Emergency bailout if postmaster has died. This is to avoid the
177 : * necessity for manual cleanup of all postmaster children. Do this less
178 : * frequently on systems for which we don't have signals to make that
179 : * cheap.
180 : */
181 2877973 : if (IsUnderPostmaster &&
182 : #ifdef POSTMASTER_POLL_RATE_LIMIT
183 : postmaster_poll_count++ % POSTMASTER_POLL_RATE_LIMIT == 0 &&
184 : #endif
185 2852525 : !PostmasterIsAlive())
186 0 : exit(1);
187 :
188 : /* Process barrier events */
189 2877973 : if (ProcSignalBarrierPending)
190 0 : ProcessProcSignalBarrier();
191 :
192 : /* Perform logging of memory contexts of this process */
193 2877973 : if (LogMemoryContextPending)
194 0 : ProcessLogMemoryContextInterrupt();
195 2877973 : }
196 :
197 :
198 : /* --------------------------------
199 : * signal handler routines
200 : * --------------------------------
201 : */
202 : static void
203 893 : StartupProcExit(int code, Datum arg)
204 : {
205 : /* Shutdown the recovery environment */
206 893 : if (standbyState != STANDBY_DISABLED)
207 114 : ShutdownRecoveryTransactionEnvironment();
208 893 : }
209 :
210 :
211 : /* ----------------------------------
212 : * Startup Process main entry point
213 : * ----------------------------------
214 : */
215 : void
216 893 : StartupProcessMain(const void *startup_data, size_t startup_data_len)
217 : {
218 : Assert(startup_data_len == 0);
219 :
220 893 : AuxiliaryProcessMainCommon();
221 :
222 : /* Arrange to clean up at startup process exit */
223 893 : on_shmem_exit(StartupProcExit, 0);
224 :
225 : /*
226 : * Properly accept or ignore signals the postmaster might send us.
227 : */
228 893 : pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */
229 893 : pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */
230 893 : pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */
231 : /* SIGQUIT handler was already set up by InitPostmasterChild */
232 893 : InitializeTimeouts(); /* establishes SIGALRM handler */
233 893 : pqsignal(SIGPIPE, SIG_IGN);
234 893 : pqsignal(SIGUSR1, procsignal_sigusr1_handler);
235 893 : pqsignal(SIGUSR2, StartupProcTriggerHandler);
236 :
237 : /*
238 : * Reset some signals that are accepted by postmaster but not here
239 : */
240 893 : pqsignal(SIGCHLD, SIG_DFL);
241 :
242 : /*
243 : * Register timeouts needed for standby mode
244 : */
245 893 : RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, StandbyDeadLockHandler);
246 893 : RegisterTimeout(STANDBY_TIMEOUT, StandbyTimeoutHandler);
247 893 : RegisterTimeout(STANDBY_LOCK_TIMEOUT, StandbyLockTimeoutHandler);
248 :
249 : /*
250 : * Unblock signals (they were blocked when the postmaster forked us)
251 : */
252 893 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
253 :
254 : /*
255 : * Do what we came for.
256 : */
257 893 : StartupXLOG();
258 :
259 : /*
260 : * Exit normally. Exit code 0 tells postmaster that we completed recovery
261 : * successfully.
262 : */
263 828 : proc_exit(0);
264 : }
265 :
266 : void
267 512 : PreRestoreCommand(void)
268 : {
269 : /*
270 : * Set in_restore_command to tell the signal handler that we should exit
271 : * right away on SIGTERM. We know that we're at a safe point to do that.
272 : * Check if we had already received the signal, so that we don't miss a
273 : * shutdown request received just before this.
274 : */
275 512 : in_restore_command = true;
276 512 : if (shutdown_requested)
277 0 : proc_exit(1);
278 512 : }
279 :
280 : void
281 511 : PostRestoreCommand(void)
282 : {
283 511 : in_restore_command = false;
284 511 : }
285 :
286 : bool
287 13388 : IsPromoteSignaled(void)
288 : {
289 13388 : return promote_signaled;
290 : }
291 :
292 : void
293 48 : ResetPromoteSignaled(void)
294 : {
295 48 : promote_signaled = false;
296 48 : }
297 :
298 : /*
299 : * Set a flag indicating that it's time to log a progress report.
300 : */
301 : void
302 27 : startup_progress_timeout_handler(void)
303 : {
304 27 : startup_progress_timer_expired = true;
305 27 : }
306 :
307 : void
308 607 : disable_startup_progress_timeout(void)
309 : {
310 : /* Feature is disabled. */
311 607 : if (log_startup_progress_interval == 0)
312 0 : return;
313 :
314 607 : disable_timeout(STARTUP_PROGRESS_TIMEOUT, false);
315 607 : startup_progress_timer_expired = false;
316 : }
317 :
318 : /*
319 : * Set the start timestamp of the current operation and enable the timeout.
320 : */
321 : void
322 495 : enable_startup_progress_timeout(void)
323 : {
324 : TimestampTz fin_time;
325 :
326 : /* Feature is disabled. */
327 495 : if (log_startup_progress_interval == 0)
328 0 : return;
329 :
330 495 : startup_progress_phase_start_time = GetCurrentTimestamp();
331 495 : fin_time = TimestampTzPlusMilliseconds(startup_progress_phase_start_time,
332 : log_startup_progress_interval);
333 495 : enable_timeout_every(STARTUP_PROGRESS_TIMEOUT, fin_time,
334 : log_startup_progress_interval);
335 : }
336 :
337 : /*
338 : * A thin wrapper to first disable and then enable the startup progress
339 : * timeout.
340 : */
341 : void
342 495 : begin_startup_progress_phase(void)
343 : {
344 : /* Feature is disabled. */
345 495 : if (log_startup_progress_interval == 0)
346 0 : return;
347 :
348 495 : disable_startup_progress_timeout();
349 495 : enable_startup_progress_timeout();
350 : }
351 :
352 : /*
353 : * Report whether startup progress timeout has occurred. Reset the timer flag
354 : * if it did, set the elapsed time to the out parameters and return true,
355 : * otherwise return false.
356 : */
357 : bool
358 327604 : has_startup_progress_timeout_expired(long *secs, int *usecs)
359 : {
360 : long seconds;
361 : int useconds;
362 : TimestampTz now;
363 :
364 : /* No timeout has occurred. */
365 327604 : if (!startup_progress_timer_expired)
366 327604 : return false;
367 :
368 : /* Calculate the elapsed time. */
369 0 : now = GetCurrentTimestamp();
370 0 : TimestampDifference(startup_progress_phase_start_time, now, &seconds, &useconds);
371 :
372 0 : *secs = seconds;
373 0 : *usecs = useconds;
374 0 : startup_progress_timer_expired = false;
375 :
376 0 : return true;
377 : }
|