LCOV - code coverage report
Current view: top level - src/backend/postmaster - startup.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 93 108 86.1 %
Date: 2025-04-24 12:15:10 Functions: 16 16 100.0 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14