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