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

Generated by: LCOV version 1.14