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-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
5247 simon@2ndQuadrant.co 93 :CBC 48 : StartupProcTriggerHandler(SIGNAL_ARGS)
94 : : {
2182 fujii@postgresql.org 95 : 48 : promote_signaled = true;
1914 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();
5247 simon@2ndQuadrant.co 105 : 32 : }
106 : :
107 : : /* SIGTERM: set flag to abort redo and exit */
108 : : static void
109 : 72 : StartupProcShutdownHandler(SIGNAL_ARGS)
110 : : {
111 [ + + ]: 72 : if (in_restore_command)
760 nathan@postgresql.or 112 :GBC 1 : proc_exit(1);
113 : : else
5247 simon@2ndQuadrant.co 114 :CBC 71 : shutdown_requested = true;
1914 fujii@postgresql.org 115 : 71 : WakeupRecovery();
5247 simon@2ndQuadrant.co 116 : 71 : }
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
2179 alvherre@alvh.no-ip. 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
375 heikki.linnakangas@i 154 : 2874929 : 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 : : */
1914 fujii@postgresql.org 163 [ + + ]: 2874929 : if (got_SIGHUP)
164 : : {
165 : 32 : got_SIGHUP = false;
2179 alvherre@alvh.no-ip. 166 : 32 : StartupRereadConfig();
167 : : }
168 : :
169 : : /*
170 : : * Check if we were requested to exit without finishing recovery.
171 : : */
5247 simon@2ndQuadrant.co 172 [ + + ]: 2874929 : 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 : : */
1829 tmunro@postgresql.or 181 [ + + ]: 2874872 : if (IsUnderPostmaster &&
182 : : #ifdef POSTMASTER_POLL_RATE_LIMIT
183 : : postmaster_poll_count++ % POSTMASTER_POLL_RATE_LIMIT == 0 &&
184 : : #endif
185 [ - + ]: 2849348 : !PostmasterIsAlive())
5247 simon@2ndQuadrant.co 186 :UBC 0 : exit(1);
187 : :
188 : : /* Process barrier events */
2278 rhaas@postgresql.org 189 [ - + ]:CBC 2874872 : if (ProcSignalBarrierPending)
2278 rhaas@postgresql.org 190 :UBC 0 : ProcessProcSignalBarrier();
191 : :
192 : : /* Perform logging of memory contexts of this process */
1524 fujii@postgresql.org 193 [ - + ]:CBC 2874872 : if (LogMemoryContextPending)
1524 fujii@postgresql.org 194 :UBC 0 : ProcessLogMemoryContextInterrupt();
5247 simon@2ndQuadrant.co 195 :CBC 2874872 : }
196 : :
197 : :
198 : : /* --------------------------------
199 : : * signal handler routines
200 : : * --------------------------------
201 : : */
202 : : static void
1804 fujii@postgresql.org 203 : 883 : StartupProcExit(int code, Datum arg)
204 : : {
205 : : /* Shutdown the recovery environment */
206 [ + + ]: 883 : if (standbyState != STANDBY_DISABLED)
207 : 114 : ShutdownRecoveryTransactionEnvironment();
208 : 883 : }
209 : :
210 : :
211 : : /* ----------------------------------
212 : : * Startup Process main entry point
213 : : * ----------------------------------
214 : : */
215 : : void
387 peter@eisentraut.org 216 : 883 : StartupProcessMain(const void *startup_data, size_t startup_data_len)
217 : : {
727 heikki.linnakangas@i 218 [ - + ]: 883 : Assert(startup_data_len == 0);
219 : :
220 : 883 : AuxiliaryProcessMainCommon();
221 : :
222 : : /* Arrange to clean up at startup process exit */
1804 fujii@postgresql.org 223 : 883 : on_shmem_exit(StartupProcExit, 0);
224 : :
225 : : /*
226 : : * Properly accept or ignore signals the postmaster might send us.
227 : : */
1914 228 : 883 : pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */
5247 simon@2ndQuadrant.co 229 : 883 : pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */
3189 tgl@sss.pgh.pa.us 230 : 883 : pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */
231 : : /* SIGQUIT handler was already set up by InitPostmasterChild */
4990 alvherre@alvh.no-ip. 232 : 883 : InitializeTimeouts(); /* establishes SIGALRM handler */
5247 simon@2ndQuadrant.co 233 : 883 : pqsignal(SIGPIPE, SIG_IGN);
2302 rhaas@postgresql.org 234 : 883 : pqsignal(SIGUSR1, procsignal_sigusr1_handler);
5247 simon@2ndQuadrant.co 235 : 883 : pqsignal(SIGUSR2, StartupProcTriggerHandler);
236 : :
237 : : /*
238 : : * Reset some signals that are accepted by postmaster but not here
239 : : */
240 : 883 : pqsignal(SIGCHLD, SIG_DFL);
241 : :
242 : : /*
243 : : * Register timeouts needed for standby mode
244 : : */
4990 alvherre@alvh.no-ip. 245 : 883 : RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, StandbyDeadLockHandler);
246 : 883 : RegisterTimeout(STANDBY_TIMEOUT, StandbyTimeoutHandler);
3657 simon@2ndQuadrant.co 247 : 883 : RegisterTimeout(STANDBY_LOCK_TIMEOUT, StandbyLockTimeoutHandler);
248 : :
249 : : /*
250 : : * Unblock signals (they were blocked when the postmaster forked us)
251 : : */
1136 tmunro@postgresql.or 252 : 883 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
253 : :
254 : : /*
255 : : * Do what we came for.
256 : : */
5247 simon@2ndQuadrant.co 257 : 883 : StartupXLOG();
258 : :
259 : : /*
260 : : * Exit normally. Exit code 0 tells postmaster that we completed recovery
261 : : * successfully.
262 : : */
263 : 818 : proc_exit(0);
264 : : }
265 : :
266 : : void
267 : 517 : 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 : 517 : in_restore_command = true;
276 [ - + ]: 517 : if (shutdown_requested)
5247 simon@2ndQuadrant.co 277 :UBC 0 : proc_exit(1);
5247 simon@2ndQuadrant.co 278 :CBC 517 : }
279 : :
280 : : void
281 : 516 : PostRestoreCommand(void)
282 : : {
283 : 516 : in_restore_command = false;
284 : 516 : }
285 : :
286 : : bool
2182 fujii@postgresql.org 287 : 11569 : IsPromoteSignaled(void)
288 : : {
289 : 11569 : return promote_signaled;
290 : : }
291 : :
292 : : void
293 : 48 : ResetPromoteSignaled(void)
294 : : {
295 : 48 : promote_signaled = false;
5247 simon@2ndQuadrant.co 296 : 48 : }
297 : :
298 : : /*
299 : : * Set a flag indicating that it's time to log a progress report.
300 : : */
301 : : void
1602 rhaas@postgresql.org 302 : 30 : startup_progress_timeout_handler(void)
303 : : {
304 : 30 : startup_progress_timer_expired = true;
305 : 30 : }
306 : :
307 : : void
1133 308 : 607 : disable_startup_progress_timeout(void)
309 : : {
310 : : /* Feature is disabled. */
311 [ - + ]: 607 : if (log_startup_progress_interval == 0)
1133 rhaas@postgresql.org 312 :UBC 0 : return;
313 : :
1133 rhaas@postgresql.org 314 :CBC 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. */
1602 327 [ - + ]: 495 : if (log_startup_progress_interval == 0)
1602 rhaas@postgresql.org 328 :UBC 0 : return;
329 : :
1602 rhaas@postgresql.org 330 :CBC 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
1133 342 : 495 : begin_startup_progress_phase(void)
343 : : {
344 : : /* Feature is disabled. */
345 [ - + ]: 495 : if (log_startup_progress_interval == 0)
1133 rhaas@postgresql.org 346 :UBC 0 : return;
347 : :
1133 rhaas@postgresql.org 348 :CBC 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
1602 358 : 326953 : 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 [ + - ]: 326953 : if (!startup_progress_timer_expired)
366 : 326953 : return false;
367 : :
368 : : /* Calculate the elapsed time. */
1602 rhaas@postgresql.org 369 :UBC 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 : : }
|