LCOV - code coverage report
Current view: top level - src/backend/postmaster - startup.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 92 106 86.8 %
Date: 2024-04-27 01:11:30 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-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          76 : StartupProcTriggerHandler(SIGNAL_ARGS)
      94             : {
      95          76 :     promote_signaled = true;
      96          76 :     WakeupRecovery();
      97          76 : }
      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          98 : StartupProcShutdownHandler(SIGNAL_ARGS)
     110             : {
     111          98 :     if (in_restore_command)
     112           0 :         proc_exit(1);
     113             :     else
     114          98 :         shutdown_requested = true;
     115          98 :     WakeupRecovery();
     116          98 : }
     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     5302516 : 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     5302516 :     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     5302516 :     if (shutdown_requested)
     173          94 :         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     5302422 :     if (IsUnderPostmaster &&
     182             : #ifdef POSTMASTER_POLL_RATE_LIMIT
     183             :         postmaster_poll_count++ % POSTMASTER_POLL_RATE_LIMIT == 0 &&
     184             : #endif
     185     5251672 :         !PostmasterIsAlive())
     186           0 :         exit(1);
     187             : 
     188             :     /* Process barrier events */
     189     5302422 :     if (ProcSignalBarrierPending)
     190           0 :         ProcessProcSignalBarrier();
     191             : 
     192             :     /* Perform logging of memory contexts of this process */
     193     5302422 :     if (LogMemoryContextPending)
     194           0 :         ProcessLogMemoryContextInterrupt();
     195     5302422 : }
     196             : 
     197             : 
     198             : /* --------------------------------
     199             :  *      signal handler routines
     200             :  * --------------------------------
     201             :  */
     202             : static void
     203        1342 : StartupProcExit(int code, Datum arg)
     204             : {
     205             :     /* Shutdown the recovery environment */
     206        1342 :     if (standbyState != STANDBY_DISABLED)
     207         186 :         ShutdownRecoveryTransactionEnvironment();
     208        1342 : }
     209             : 
     210             : 
     211             : /* ----------------------------------
     212             :  *  Startup Process main entry point
     213             :  * ----------------------------------
     214             :  */
     215             : void
     216        1342 : StartupProcessMain(char *startup_data, size_t startup_data_len)
     217             : {
     218             :     Assert(startup_data_len == 0);
     219             : 
     220        1342 :     MyBackendType = B_STARTUP;
     221        1342 :     AuxiliaryProcessMainCommon();
     222             : 
     223             :     /* Arrange to clean up at startup process exit */
     224        1342 :     on_shmem_exit(StartupProcExit, 0);
     225             : 
     226             :     /*
     227             :      * Properly accept or ignore signals the postmaster might send us.
     228             :      */
     229        1342 :     pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */
     230        1342 :     pqsignal(SIGINT, SIG_IGN);  /* ignore query cancel */
     231        1342 :     pqsignal(SIGTERM, StartupProcShutdownHandler);  /* request shutdown */
     232             :     /* SIGQUIT handler was already set up by InitPostmasterChild */
     233        1342 :     InitializeTimeouts();       /* establishes SIGALRM handler */
     234        1342 :     pqsignal(SIGPIPE, SIG_IGN);
     235        1342 :     pqsignal(SIGUSR1, procsignal_sigusr1_handler);
     236        1342 :     pqsignal(SIGUSR2, StartupProcTriggerHandler);
     237             : 
     238             :     /*
     239             :      * Reset some signals that are accepted by postmaster but not here
     240             :      */
     241        1342 :     pqsignal(SIGCHLD, SIG_DFL);
     242             : 
     243             :     /*
     244             :      * Register timeouts needed for standby mode
     245             :      */
     246        1342 :     RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, StandbyDeadLockHandler);
     247        1342 :     RegisterTimeout(STANDBY_TIMEOUT, StandbyTimeoutHandler);
     248        1342 :     RegisterTimeout(STANDBY_LOCK_TIMEOUT, StandbyLockTimeoutHandler);
     249             : 
     250             :     /*
     251             :      * Unblock signals (they were blocked when the postmaster forked us)
     252             :      */
     253        1342 :     sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
     254             : 
     255             :     /*
     256             :      * Do what we came for.
     257             :      */
     258        1342 :     StartupXLOG();
     259             : 
     260             :     /*
     261             :      * Exit normally. Exit code 0 tells postmaster that we completed recovery
     262             :      * successfully.
     263             :      */
     264        1242 :     proc_exit(0);
     265             : }
     266             : 
     267             : void
     268         318 : 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         318 :     in_restore_command = true;
     277         318 :     if (shutdown_requested)
     278           0 :         proc_exit(1);
     279         318 : }
     280             : 
     281             : void
     282         318 : PostRestoreCommand(void)
     283             : {
     284         318 :     in_restore_command = false;
     285         318 : }
     286             : 
     287             : bool
     288       30786 : IsPromoteSignaled(void)
     289             : {
     290       30786 :     return promote_signaled;
     291             : }
     292             : 
     293             : void
     294          76 : ResetPromoteSignaled(void)
     295             : {
     296          76 :     promote_signaled = false;
     297          76 : }
     298             : 
     299             : /*
     300             :  * Set a flag indicating that it's time to log a progress report.
     301             :  */
     302             : void
     303          12 : startup_progress_timeout_handler(void)
     304             : {
     305          12 :     startup_progress_timer_expired = true;
     306          12 : }
     307             : 
     308             : void
     309        1068 : disable_startup_progress_timeout(void)
     310             : {
     311             :     /* Feature is disabled. */
     312        1068 :     if (log_startup_progress_interval == 0)
     313           0 :         return;
     314             : 
     315        1068 :     disable_timeout(STARTUP_PROGRESS_TIMEOUT, false);
     316        1068 :     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         888 : enable_startup_progress_timeout(void)
     324             : {
     325             :     TimestampTz fin_time;
     326             : 
     327             :     /* Feature is disabled. */
     328         888 :     if (log_startup_progress_interval == 0)
     329           0 :         return;
     330             : 
     331         888 :     startup_progress_phase_start_time = GetCurrentTimestamp();
     332         888 :     fin_time = TimestampTzPlusMilliseconds(startup_progress_phase_start_time,
     333             :                                            log_startup_progress_interval);
     334         888 :     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         888 : begin_startup_progress_phase(void)
     344             : {
     345             :     /* Feature is disabled. */
     346         888 :     if (log_startup_progress_interval == 0)
     347           0 :         return;
     348             : 
     349         888 :     disable_startup_progress_timeout();
     350         888 :     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      545796 : 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      545796 :     if (!startup_progress_timer_expired)
     367      545796 :         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             : }

Generated by: LCOV version 1.14