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