Age Owner Branch data 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-2024, 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 HandleStartupProcInterrupts().
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
4547 simon@2ndQuadrant.co 93 :CBC 39 : StartupProcTriggerHandler(SIGNAL_ARGS)
94 : : {
1482 fujii@postgresql.org 95 : 39 : promote_signaled = true;
1214 96 : 39 : WakeupRecovery();
97 : 39 : }
98 : :
99 : : /* SIGHUP: set flag to re-read config file at next convenient time */
100 : : static void
101 : 27 : StartupProcSigHupHandler(SIGNAL_ARGS)
102 : : {
103 : 27 : got_SIGHUP = true;
104 : 27 : WakeupRecovery();
4547 simon@2ndQuadrant.co 105 : 27 : }
106 : :
107 : : /* SIGTERM: set flag to abort redo and exit */
108 : : static void
109 : 48 : StartupProcShutdownHandler(SIGNAL_ARGS)
110 : : {
111 [ - + ]: 48 : if (in_restore_command)
60 nathan@postgresql.or 112 :UNC 0 : proc_exit(1);
113 : : else
4547 simon@2ndQuadrant.co 114 :CBC 48 : shutdown_requested = true;
1214 fujii@postgresql.org 115 : 48 : WakeupRecovery();
4547 simon@2ndQuadrant.co 116 : 48 : }
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
1479 alvherre@alvh.no-ip. 125 : 27 : StartupRereadConfig(void)
126 : : {
127 : 27 : char *conninfo = pstrdup(PrimaryConnInfo);
128 : 27 : char *slotname = pstrdup(PrimarySlotName);
129 : 27 : bool tempSlot = wal_receiver_create_temp_slot;
130 : : bool conninfoChanged;
131 : : bool slotnameChanged;
132 : 27 : bool tempSlotChanged = false;
133 : :
134 : 27 : ProcessConfigFile(PGC_SIGHUP);
135 : :
136 : 27 : conninfoChanged = strcmp(conninfo, PrimaryConnInfo) != 0;
137 : 27 : 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 [ + + + + ]: 27 : if (!slotnameChanged && strcmp(PrimarySlotName, "") == 0)
144 : 3 : tempSlotChanged = tempSlot != wal_receiver_create_temp_slot;
145 : 27 : pfree(conninfo);
146 : 27 : pfree(slotname);
147 : :
148 [ + + + + : 27 : if (conninfoChanged || slotnameChanged || tempSlotChanged)
- + ]
149 : 5 : StartupRequestWalReceiverRestart();
150 : 27 : }
151 : :
152 : : /* Handle various signals that might be sent to the startup process */
153 : : void
4547 simon@2ndQuadrant.co 154 : 2995977 : HandleStartupProcInterrupts(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 : : */
1214 fujii@postgresql.org 163 [ + + ]: 2995977 : if (got_SIGHUP)
164 : : {
165 : 27 : got_SIGHUP = false;
1479 alvherre@alvh.no-ip. 166 : 27 : StartupRereadConfig();
167 : : }
168 : :
169 : : /*
170 : : * Check if we were requested to exit without finishing recovery.
171 : : */
4547 simon@2ndQuadrant.co 172 [ + + ]: 2995977 : if (shutdown_requested)
173 : 47 : 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 : : */
1129 tmunro@postgresql.or 181 [ + + ]: 2995930 : if (IsUnderPostmaster &&
182 : : #ifdef POSTMASTER_POLL_RATE_LIMIT
183 : : postmaster_poll_count++ % POSTMASTER_POLL_RATE_LIMIT == 0 &&
184 : : #endif
185 [ - + ]: 2970471 : !PostmasterIsAlive())
4547 simon@2ndQuadrant.co 186 :UBC 0 : exit(1);
187 : :
188 : : /* Process barrier events */
1578 rhaas@postgresql.org 189 [ - + ]:CBC 2995930 : if (ProcSignalBarrierPending)
1578 rhaas@postgresql.org 190 :UBC 0 : ProcessProcSignalBarrier();
191 : :
192 : : /* Perform logging of memory contexts of this process */
824 fujii@postgresql.org 193 [ - + ]:CBC 2995930 : if (LogMemoryContextPending)
824 fujii@postgresql.org 194 :UBC 0 : ProcessLogMemoryContextInterrupt();
4547 simon@2ndQuadrant.co 195 :CBC 2995930 : }
196 : :
197 : :
198 : : /* --------------------------------
199 : : * signal handler routines
200 : : * --------------------------------
201 : : */
202 : : static void
1104 fujii@postgresql.org 203 : 692 : StartupProcExit(int code, Datum arg)
204 : : {
205 : : /* Shutdown the recovery environment */
206 [ + + ]: 692 : if (standbyState != STANDBY_DISABLED)
207 : 94 : ShutdownRecoveryTransactionEnvironment();
208 : 692 : }
209 : :
210 : :
211 : : /* ----------------------------------
212 : : * Startup Process main entry point
213 : : * ----------------------------------
214 : : */
215 : : void
27 heikki.linnakangas@i 216 :GNC 736 : StartupProcessMain(char *startup_data, size_t startup_data_len)
217 : : {
218 [ - + ]: 736 : Assert(startup_data_len == 0);
219 : :
220 : 736 : MyBackendType = B_STARTUP;
221 : 736 : AuxiliaryProcessMainCommon();
222 : :
223 : : /* Arrange to clean up at startup process exit */
1104 fujii@postgresql.org 224 :CBC 736 : on_shmem_exit(StartupProcExit, 0);
225 : :
226 : : /*
227 : : * Properly accept or ignore signals the postmaster might send us.
228 : : */
1214 229 : 736 : pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */
4547 simon@2ndQuadrant.co 230 : 736 : pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */
2489 tgl@sss.pgh.pa.us 231 : 736 : pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */
232 : : /* SIGQUIT handler was already set up by InitPostmasterChild */
4290 alvherre@alvh.no-ip. 233 : 736 : InitializeTimeouts(); /* establishes SIGALRM handler */
4547 simon@2ndQuadrant.co 234 : 736 : pqsignal(SIGPIPE, SIG_IGN);
1602 rhaas@postgresql.org 235 : 736 : pqsignal(SIGUSR1, procsignal_sigusr1_handler);
4547 simon@2ndQuadrant.co 236 : 736 : pqsignal(SIGUSR2, StartupProcTriggerHandler);
237 : :
238 : : /*
239 : : * Reset some signals that are accepted by postmaster but not here
240 : : */
241 : 736 : pqsignal(SIGCHLD, SIG_DFL);
242 : :
243 : : /*
244 : : * Register timeouts needed for standby mode
245 : : */
4290 alvherre@alvh.no-ip. 246 : 736 : RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, StandbyDeadLockHandler);
247 : 736 : RegisterTimeout(STANDBY_TIMEOUT, StandbyTimeoutHandler);
2957 simon@2ndQuadrant.co 248 : 736 : RegisterTimeout(STANDBY_LOCK_TIMEOUT, StandbyLockTimeoutHandler);
249 : :
250 : : /*
251 : : * Unblock signals (they were blocked when the postmaster forked us)
252 : : */
436 tmunro@postgresql.or 253 : 736 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
254 : :
255 : : /*
256 : : * Do what we came for.
257 : : */
4547 simon@2ndQuadrant.co 258 : 736 : StartupXLOG();
259 : :
260 : : /*
261 : : * Exit normally. Exit code 0 tells postmaster that we completed recovery
262 : : * successfully.
263 : : */
264 : 642 : proc_exit(0);
265 : : }
266 : :
267 : : void
268 : 307 : PreRestoreCommand(void)
269 : : {
270 : : /*
271 : : * Set in_restore_command to tell the signal handler that we should exit
272 : : * right away on SIGTERM. We know that we're at a safe point to do that.
273 : : * Check if we had already received the signal, so that we don't miss a
274 : : * shutdown request received just before this.
275 : : */
276 : 307 : in_restore_command = true;
277 [ - + ]: 307 : if (shutdown_requested)
4547 simon@2ndQuadrant.co 278 :UBC 0 : proc_exit(1);
4547 simon@2ndQuadrant.co 279 :CBC 307 : }
280 : :
281 : : void
282 : 307 : PostRestoreCommand(void)
283 : : {
284 : 307 : in_restore_command = false;
285 : 307 : }
286 : :
287 : : bool
1482 fujii@postgresql.org 288 : 13588 : IsPromoteSignaled(void)
289 : : {
290 : 13588 : return promote_signaled;
291 : : }
292 : :
293 : : void
294 : 39 : ResetPromoteSignaled(void)
295 : : {
296 : 39 : promote_signaled = false;
4547 simon@2ndQuadrant.co 297 : 39 : }
298 : :
299 : : /*
300 : : * Set a flag indicating that it's time to log a progress report.
301 : : */
302 : : void
902 rhaas@postgresql.org 303 : 26 : startup_progress_timeout_handler(void)
304 : : {
305 : 26 : startup_progress_timer_expired = true;
306 : 26 : }
307 : :
308 : : void
433 309 : 630 : disable_startup_progress_timeout(void)
310 : : {
311 : : /* Feature is disabled. */
312 [ - + ]: 630 : if (log_startup_progress_interval == 0)
433 rhaas@postgresql.org 313 :UBC 0 : return;
314 : :
433 rhaas@postgresql.org 315 :CBC 630 : disable_timeout(STARTUP_PROGRESS_TIMEOUT, false);
316 : 630 : startup_progress_timer_expired = false;
317 : : }
318 : :
319 : : /*
320 : : * Set the start timestamp of the current operation and enable the timeout.
321 : : */
322 : : void
323 : 495 : enable_startup_progress_timeout(void)
324 : : {
325 : : TimestampTz fin_time;
326 : :
327 : : /* Feature is disabled. */
902 328 [ - + ]: 495 : if (log_startup_progress_interval == 0)
902 rhaas@postgresql.org 329 :UBC 0 : return;
330 : :
902 rhaas@postgresql.org 331 :CBC 495 : startup_progress_phase_start_time = GetCurrentTimestamp();
332 : 495 : fin_time = TimestampTzPlusMilliseconds(startup_progress_phase_start_time,
333 : : log_startup_progress_interval);
334 : 495 : enable_timeout_every(STARTUP_PROGRESS_TIMEOUT, fin_time,
335 : : log_startup_progress_interval);
336 : : }
337 : :
338 : : /*
339 : : * A thin wrapper to first disable and then enable the startup progress
340 : : * timeout.
341 : : */
342 : : void
433 343 : 495 : begin_startup_progress_phase(void)
344 : : {
345 : : /* Feature is disabled. */
346 [ - + ]: 495 : if (log_startup_progress_interval == 0)
433 rhaas@postgresql.org 347 :UBC 0 : return;
348 : :
433 rhaas@postgresql.org 349 :CBC 495 : disable_startup_progress_timeout();
350 : 495 : enable_startup_progress_timeout();
351 : : }
352 : :
353 : : /*
354 : : * Report whether startup progress timeout has occurred. Reset the timer flag
355 : : * if it did, set the elapsed time to the out parameters and return true,
356 : : * otherwise return false.
357 : : */
358 : : bool
902 359 : 272210 : has_startup_progress_timeout_expired(long *secs, int *usecs)
360 : : {
361 : : long seconds;
362 : : int useconds;
363 : : TimestampTz now;
364 : :
365 : : /* No timeout has occurred. */
366 [ + - ]: 272210 : if (!startup_progress_timer_expired)
367 : 272210 : return false;
368 : :
369 : : /* Calculate the elapsed time. */
902 rhaas@postgresql.org 370 :UBC 0 : now = GetCurrentTimestamp();
371 : 0 : TimestampDifference(startup_progress_phase_start_time, now, &seconds, &useconds);
372 : :
373 : 0 : *secs = seconds;
374 : 0 : *usecs = useconds;
375 : 0 : startup_progress_timer_expired = false;
376 : :
377 : 0 : return true;
378 : : }
|