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