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 93 80 : StartupProcTriggerHandler(SIGNAL_ARGS) 94 : { 95 80 : promote_signaled = true; 96 80 : WakeupRecovery(); 97 80 : } 98 : 99 : /* SIGHUP: set flag to re-read config file at next convenient time */ 100 : static void 101 46 : StartupProcSigHupHandler(SIGNAL_ARGS) 102 : { 103 46 : got_SIGHUP = true; 104 46 : WakeupRecovery(); 105 46 : } 106 : 107 : /* SIGTERM: set flag to abort redo and exit */ 108 : static void 109 104 : StartupProcShutdownHandler(SIGNAL_ARGS) 110 : { 111 104 : if (in_restore_command) 112 0 : proc_exit(1); 113 : else 114 104 : shutdown_requested = true; 115 104 : WakeupRecovery(); 116 104 : } 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 46 : StartupRereadConfig(void) 126 : { 127 46 : char *conninfo = pstrdup(PrimaryConnInfo); 128 46 : char *slotname = pstrdup(PrimarySlotName); 129 46 : bool tempSlot = wal_receiver_create_temp_slot; 130 : bool conninfoChanged; 131 : bool slotnameChanged; 132 46 : bool tempSlotChanged = false; 133 : 134 46 : ProcessConfigFile(PGC_SIGHUP); 135 : 136 46 : conninfoChanged = strcmp(conninfo, PrimaryConnInfo) != 0; 137 46 : 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 46 : if (!slotnameChanged && strcmp(PrimarySlotName, "") == 0) 144 6 : tempSlotChanged = tempSlot != wal_receiver_create_temp_slot; 145 46 : pfree(conninfo); 146 46 : pfree(slotname); 147 : 148 46 : if (conninfoChanged || slotnameChanged || tempSlotChanged) 149 6 : StartupRequestWalReceiverRestart(); 150 46 : } 151 : 152 : /* Handle various signals that might be sent to the startup process */ 153 : void 154 5213882 : 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 : */ 163 5213882 : if (got_SIGHUP) 164 : { 165 46 : got_SIGHUP = false; 166 46 : StartupRereadConfig(); 167 : } 168 : 169 : /* 170 : * Check if we were requested to exit without finishing recovery. 171 : */ 172 5213882 : if (shutdown_requested) 173 100 : 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 5213782 : if (IsUnderPostmaster && 182 : #ifdef POSTMASTER_POLL_RATE_LIMIT 183 : postmaster_poll_count++ % POSTMASTER_POLL_RATE_LIMIT == 0 && 184 : #endif 185 5163036 : !PostmasterIsAlive()) 186 0 : exit(1); 187 : 188 : /* Process barrier events */ 189 5213782 : if (ProcSignalBarrierPending) 190 0 : ProcessProcSignalBarrier(); 191 : 192 : /* Perform logging of memory contexts of this process */ 193 5213782 : if (LogMemoryContextPending) 194 0 : ProcessLogMemoryContextInterrupt(); 195 5213782 : } 196 : 197 : 198 : /* -------------------------------- 199 : * signal handler routines 200 : * -------------------------------- 201 : */ 202 : static void 203 1380 : StartupProcExit(int code, Datum arg) 204 : { 205 : /* Shutdown the recovery environment */ 206 1380 : if (standbyState != STANDBY_DISABLED) 207 198 : ShutdownRecoveryTransactionEnvironment(); 208 1380 : } 209 : 210 : 211 : /* ---------------------------------- 212 : * Startup Process main entry point 213 : * ---------------------------------- 214 : */ 215 : void 216 1380 : StartupProcessMain(char *startup_data, size_t startup_data_len) 217 : { 218 : Assert(startup_data_len == 0); 219 : 220 1380 : MyBackendType = B_STARTUP; 221 1380 : AuxiliaryProcessMainCommon(); 222 : 223 : /* Arrange to clean up at startup process exit */ 224 1380 : on_shmem_exit(StartupProcExit, 0); 225 : 226 : /* 227 : * Properly accept or ignore signals the postmaster might send us. 228 : */ 229 1380 : pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */ 230 1380 : pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */ 231 1380 : pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */ 232 : /* SIGQUIT handler was already set up by InitPostmasterChild */ 233 1380 : InitializeTimeouts(); /* establishes SIGALRM handler */ 234 1380 : pqsignal(SIGPIPE, SIG_IGN); 235 1380 : pqsignal(SIGUSR1, procsignal_sigusr1_handler); 236 1380 : pqsignal(SIGUSR2, StartupProcTriggerHandler); 237 : 238 : /* 239 : * Reset some signals that are accepted by postmaster but not here 240 : */ 241 1380 : pqsignal(SIGCHLD, SIG_DFL); 242 : 243 : /* 244 : * Register timeouts needed for standby mode 245 : */ 246 1380 : RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, StandbyDeadLockHandler); 247 1380 : RegisterTimeout(STANDBY_TIMEOUT, StandbyTimeoutHandler); 248 1380 : RegisterTimeout(STANDBY_LOCK_TIMEOUT, StandbyLockTimeoutHandler); 249 : 250 : /* 251 : * Unblock signals (they were blocked when the postmaster forked us) 252 : */ 253 1380 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL); 254 : 255 : /* 256 : * Do what we came for. 257 : */ 258 1380 : StartupXLOG(); 259 : 260 : /* 261 : * Exit normally. Exit code 0 tells postmaster that we completed recovery 262 : * successfully. 263 : */ 264 1272 : proc_exit(0); 265 : } 266 : 267 : void 268 374 : 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 374 : in_restore_command = true; 277 374 : if (shutdown_requested) 278 0 : proc_exit(1); 279 374 : } 280 : 281 : void 282 374 : PostRestoreCommand(void) 283 : { 284 374 : in_restore_command = false; 285 374 : } 286 : 287 : bool 288 29382 : IsPromoteSignaled(void) 289 : { 290 29382 : return promote_signaled; 291 : } 292 : 293 : void 294 80 : ResetPromoteSignaled(void) 295 : { 296 80 : promote_signaled = false; 297 80 : } 298 : 299 : /* 300 : * Set a flag indicating that it's time to log a progress report. 301 : */ 302 : void 303 14 : startup_progress_timeout_handler(void) 304 : { 305 14 : startup_progress_timer_expired = true; 306 14 : } 307 : 308 : void 309 1104 : disable_startup_progress_timeout(void) 310 : { 311 : /* Feature is disabled. */ 312 1104 : if (log_startup_progress_interval == 0) 313 0 : return; 314 : 315 1104 : disable_timeout(STARTUP_PROGRESS_TIMEOUT, false); 316 1104 : 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 912 : enable_startup_progress_timeout(void) 324 : { 325 : TimestampTz fin_time; 326 : 327 : /* Feature is disabled. */ 328 912 : if (log_startup_progress_interval == 0) 329 0 : return; 330 : 331 912 : startup_progress_phase_start_time = GetCurrentTimestamp(); 332 912 : fin_time = TimestampTzPlusMilliseconds(startup_progress_phase_start_time, 333 : log_startup_progress_interval); 334 912 : 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 343 912 : begin_startup_progress_phase(void) 344 : { 345 : /* Feature is disabled. */ 346 912 : if (log_startup_progress_interval == 0) 347 0 : return; 348 : 349 912 : disable_startup_progress_timeout(); 350 912 : 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 359 545364 : 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 545364 : if (!startup_progress_timer_expired) 367 545364 : return false; 368 : 369 : /* Calculate the elapsed time. */ 370 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 : }