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 95 72 : StartupProcTriggerHandler(SIGNAL_ARGS) 96 : { 97 72 : int save_errno = errno; 98 : 99 72 : promote_signaled = true; 100 72 : WakeupRecovery(); 101 : 102 72 : errno = save_errno; 103 72 : } 104 : 105 : /* SIGHUP: set flag to re-read config file at next convenient time */ 106 : static void 107 28 : StartupProcSigHupHandler(SIGNAL_ARGS) 108 : { 109 28 : int save_errno = errno; 110 : 111 28 : got_SIGHUP = true; 112 28 : WakeupRecovery(); 113 : 114 28 : errno = save_errno; 115 28 : } 116 : 117 : /* SIGTERM: set flag to abort redo and exit */ 118 : static void 119 62 : StartupProcShutdownHandler(SIGNAL_ARGS) 120 : { 121 62 : int save_errno = errno; 122 : 123 62 : if (in_restore_command) 124 0 : proc_exit(1); 125 : else 126 62 : shutdown_requested = true; 127 62 : WakeupRecovery(); 128 : 129 62 : errno = save_errno; 130 62 : } 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 139 28 : StartupRereadConfig(void) 140 : { 141 28 : char *conninfo = pstrdup(PrimaryConnInfo); 142 28 : char *slotname = pstrdup(PrimarySlotName); 143 28 : bool tempSlot = wal_receiver_create_temp_slot; 144 : bool conninfoChanged; 145 : bool slotnameChanged; 146 28 : bool tempSlotChanged = false; 147 : 148 28 : ProcessConfigFile(PGC_SIGHUP); 149 : 150 28 : conninfoChanged = strcmp(conninfo, PrimaryConnInfo) != 0; 151 28 : 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 28 : if (!slotnameChanged && strcmp(PrimarySlotName, "") == 0) 158 6 : tempSlotChanged = tempSlot != wal_receiver_create_temp_slot; 159 28 : pfree(conninfo); 160 28 : pfree(slotname); 161 : 162 28 : if (conninfoChanged || slotnameChanged || tempSlotChanged) 163 0 : StartupRequestWalReceiverRestart(); 164 28 : } 165 : 166 : /* Handle various signals that might be sent to the startup process */ 167 : void 168 5040504 : 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 : */ 177 5040504 : if (got_SIGHUP) 178 : { 179 28 : got_SIGHUP = false; 180 28 : StartupRereadConfig(); 181 : } 182 : 183 : /* 184 : * Check if we were requested to exit without finishing recovery. 185 : */ 186 5040504 : if (shutdown_requested) 187 62 : 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 : */ 195 5040442 : if (IsUnderPostmaster && 196 : #ifdef POSTMASTER_POLL_RATE_LIMIT 197 : postmaster_poll_count++ % POSTMASTER_POLL_RATE_LIMIT == 0 && 198 : #endif 199 4989548 : !PostmasterIsAlive()) 200 0 : exit(1); 201 : 202 : /* Process barrier events */ 203 5040442 : if (ProcSignalBarrierPending) 204 0 : ProcessProcSignalBarrier(); 205 : 206 : /* Perform logging of memory contexts of this process */ 207 5040442 : if (LogMemoryContextPending) 208 0 : ProcessLogMemoryContextInterrupt(); 209 5040442 : } 210 : 211 : 212 : /* -------------------------------- 213 : * signal handler routines 214 : * -------------------------------- 215 : */ 216 : static void 217 1108 : StartupProcExit(int code, Datum arg) 218 : { 219 : /* Shutdown the recovery environment */ 220 1108 : if (standbyState != STANDBY_DISABLED) 221 142 : ShutdownRecoveryTransactionEnvironment(); 222 1108 : } 223 : 224 : 225 : /* ---------------------------------- 226 : * Startup Process main entry point 227 : * ---------------------------------- 228 : */ 229 : void 230 1108 : StartupProcessMain(void) 231 : { 232 : /* Arrange to clean up at startup process exit */ 233 1108 : on_shmem_exit(StartupProcExit, 0); 234 : 235 : /* 236 : * Properly accept or ignore signals the postmaster might send us. 237 : */ 238 1108 : pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */ 239 1108 : pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */ 240 1108 : pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */ 241 : /* SIGQUIT handler was already set up by InitPostmasterChild */ 242 1108 : InitializeTimeouts(); /* establishes SIGALRM handler */ 243 1108 : pqsignal(SIGPIPE, SIG_IGN); 244 1108 : pqsignal(SIGUSR1, procsignal_sigusr1_handler); 245 1108 : pqsignal(SIGUSR2, StartupProcTriggerHandler); 246 : 247 : /* 248 : * Reset some signals that are accepted by postmaster but not here 249 : */ 250 1108 : pqsignal(SIGCHLD, SIG_DFL); 251 : 252 : /* 253 : * Register timeouts needed for standby mode 254 : */ 255 1108 : RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, StandbyDeadLockHandler); 256 1108 : RegisterTimeout(STANDBY_TIMEOUT, StandbyTimeoutHandler); 257 1108 : RegisterTimeout(STANDBY_LOCK_TIMEOUT, StandbyLockTimeoutHandler); 258 : 259 : /* 260 : * Unblock signals (they were blocked when the postmaster forked us) 261 : */ 262 1108 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL); 263 : 264 : /* 265 : * Do what we came for. 266 : */ 267 1108 : StartupXLOG(); 268 : 269 : /* 270 : * Exit normally. Exit code 0 tells postmaster that we completed recovery 271 : * successfully. 272 : */ 273 1040 : proc_exit(0); 274 : } 275 : 276 : void 277 236 : 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 236 : in_restore_command = true; 286 236 : if (shutdown_requested) 287 0 : proc_exit(1); 288 236 : } 289 : 290 : void 291 236 : PostRestoreCommand(void) 292 : { 293 236 : in_restore_command = false; 294 236 : } 295 : 296 : bool 297 28034 : IsPromoteSignaled(void) 298 : { 299 28034 : return promote_signaled; 300 : } 301 : 302 : void 303 72 : ResetPromoteSignaled(void) 304 : { 305 72 : promote_signaled = false; 306 72 : } 307 : 308 : /* 309 : * Set a flag indicating that it's time to log a progress report. 310 : */ 311 : void 312 12 : startup_progress_timeout_handler(void) 313 : { 314 12 : startup_progress_timer_expired = true; 315 12 : } 316 : 317 : void 318 858 : disable_startup_progress_timeout(void) 319 : { 320 : /* Feature is disabled. */ 321 858 : if (log_startup_progress_interval == 0) 322 0 : return; 323 : 324 858 : disable_timeout(STARTUP_PROGRESS_TIMEOUT, false); 325 858 : 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 722 : enable_startup_progress_timeout(void) 333 : { 334 : TimestampTz fin_time; 335 : 336 : /* Feature is disabled. */ 337 722 : if (log_startup_progress_interval == 0) 338 0 : return; 339 : 340 722 : startup_progress_phase_start_time = GetCurrentTimestamp(); 341 722 : fin_time = TimestampTzPlusMilliseconds(startup_progress_phase_start_time, 342 : log_startup_progress_interval); 343 722 : 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 352 722 : begin_startup_progress_phase(void) 353 : { 354 : /* Feature is disabled. */ 355 722 : if (log_startup_progress_interval == 0) 356 0 : return; 357 : 358 722 : disable_startup_progress_timeout(); 359 722 : 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 368 512892 : 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 512892 : if (!startup_progress_timer_expired) 376 512892 : return false; 377 : 378 : /* Calculate the elapsed time. */ 379 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 : }