LCOV - code coverage report
Current view: top level - src/backend/postmaster - startup.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 88 100 88.0 %
Date: 2021-12-09 04:09:06 Functions: 14 14 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-2021, 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/xlogutils.h"
      24             : #include "libpq/pqsignal.h"
      25             : #include "miscadmin.h"
      26             : #include "pgstat.h"
      27             : #include "postmaster/interrupt.h"
      28             : #include "postmaster/startup.h"
      29             : #include "storage/ipc.h"
      30             : #include "storage/latch.h"
      31             : #include "storage/pmsignal.h"
      32             : #include "storage/procsignal.h"
      33             : #include "storage/standby.h"
      34             : #include "utils/guc.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          64 : StartupProcTriggerHandler(SIGNAL_ARGS)
      94             : {
      95          64 :     int         save_errno = errno;
      96             : 
      97          64 :     promote_signaled = true;
      98          64 :     WakeupRecovery();
      99             : 
     100          64 :     errno = save_errno;
     101          64 : }
     102             : 
     103             : /* SIGHUP: set flag to re-read config file at next convenient time */
     104             : static void
     105           6 : StartupProcSigHupHandler(SIGNAL_ARGS)
     106             : {
     107           6 :     int         save_errno = errno;
     108             : 
     109           6 :     got_SIGHUP = true;
     110           6 :     WakeupRecovery();
     111             : 
     112           6 :     errno = save_errno;
     113           6 : }
     114             : 
     115             : /* SIGTERM: set flag to abort redo and exit */
     116             : static void
     117          46 : StartupProcShutdownHandler(SIGNAL_ARGS)
     118             : {
     119          46 :     int         save_errno = errno;
     120             : 
     121          46 :     if (in_restore_command)
     122           0 :         proc_exit(1);
     123             :     else
     124          46 :         shutdown_requested = true;
     125          46 :     WakeupRecovery();
     126             : 
     127          46 :     errno = save_errno;
     128          46 : }
     129             : 
     130             : /*
     131             :  * Re-read the config file.
     132             :  *
     133             :  * If one of the critical walreceiver options has changed, flag xlog.c
     134             :  * to restart it.
     135             :  */
     136             : static void
     137           6 : StartupRereadConfig(void)
     138             : {
     139           6 :     char       *conninfo = pstrdup(PrimaryConnInfo);
     140           6 :     char       *slotname = pstrdup(PrimarySlotName);
     141           6 :     bool        tempSlot = wal_receiver_create_temp_slot;
     142             :     bool        conninfoChanged;
     143             :     bool        slotnameChanged;
     144           6 :     bool        tempSlotChanged = false;
     145             : 
     146           6 :     ProcessConfigFile(PGC_SIGHUP);
     147             : 
     148           6 :     conninfoChanged = strcmp(conninfo, PrimaryConnInfo) != 0;
     149           6 :     slotnameChanged = strcmp(slotname, PrimarySlotName) != 0;
     150             : 
     151             :     /*
     152             :      * wal_receiver_create_temp_slot is used only when we have no slot
     153             :      * configured.  We do not need to track this change if it has no effect.
     154             :      */
     155           6 :     if (!slotnameChanged && strcmp(PrimarySlotName, "") == 0)
     156           2 :         tempSlotChanged = tempSlot != wal_receiver_create_temp_slot;
     157           6 :     pfree(conninfo);
     158           6 :     pfree(slotname);
     159             : 
     160           6 :     if (conninfoChanged || slotnameChanged || tempSlotChanged)
     161           0 :         StartupRequestWalReceiverRestart();
     162           6 : }
     163             : 
     164             : /* Handle various signals that might be sent to the startup process */
     165             : void
     166      850592 : HandleStartupProcInterrupts(void)
     167             : {
     168             : #ifdef POSTMASTER_POLL_RATE_LIMIT
     169             :     static uint32 postmaster_poll_count = 0;
     170             : #endif
     171             : 
     172             :     /*
     173             :      * Process any requests or signals received recently.
     174             :      */
     175      850592 :     if (got_SIGHUP)
     176             :     {
     177           6 :         got_SIGHUP = false;
     178           6 :         StartupRereadConfig();
     179             :     }
     180             : 
     181             :     /*
     182             :      * Check if we were requested to exit without finishing recovery.
     183             :      */
     184      850592 :     if (shutdown_requested)
     185          46 :         proc_exit(1);
     186             : 
     187             :     /*
     188             :      * Emergency bailout if postmaster has died.  This is to avoid the
     189             :      * necessity for manual cleanup of all postmaster children.  Do this less
     190             :      * frequently on systems for which we don't have signals to make that
     191             :      * cheap.
     192             :      */
     193      850546 :     if (IsUnderPostmaster &&
     194             : #ifdef POSTMASTER_POLL_RATE_LIMIT
     195             :         postmaster_poll_count++ % POSTMASTER_POLL_RATE_LIMIT == 0 &&
     196             : #endif
     197      809558 :         !PostmasterIsAlive())
     198           0 :         exit(1);
     199             : 
     200             :     /* Process barrier events */
     201      850546 :     if (ProcSignalBarrierPending)
     202           0 :         ProcessProcSignalBarrier();
     203      850546 : }
     204             : 
     205             : 
     206             : /* --------------------------------
     207             :  *      signal handler routines
     208             :  * --------------------------------
     209             :  */
     210             : static void
     211         878 : StartupProcExit(int code, Datum arg)
     212             : {
     213             :     /* Shutdown the recovery environment */
     214         878 :     if (standbyState != STANDBY_DISABLED)
     215         114 :         ShutdownRecoveryTransactionEnvironment();
     216         878 : }
     217             : 
     218             : 
     219             : /* ----------------------------------
     220             :  *  Startup Process main entry point
     221             :  * ----------------------------------
     222             :  */
     223             : void
     224         878 : StartupProcessMain(void)
     225             : {
     226             :     /* Arrange to clean up at startup process exit */
     227         878 :     on_shmem_exit(StartupProcExit, 0);
     228             : 
     229             :     /*
     230             :      * Properly accept or ignore signals the postmaster might send us.
     231             :      */
     232         878 :     pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */
     233         878 :     pqsignal(SIGINT, SIG_IGN);  /* ignore query cancel */
     234         878 :     pqsignal(SIGTERM, StartupProcShutdownHandler);  /* request shutdown */
     235             :     /* SIGQUIT handler was already set up by InitPostmasterChild */
     236         878 :     InitializeTimeouts();       /* establishes SIGALRM handler */
     237         878 :     pqsignal(SIGPIPE, SIG_IGN);
     238         878 :     pqsignal(SIGUSR1, procsignal_sigusr1_handler);
     239         878 :     pqsignal(SIGUSR2, StartupProcTriggerHandler);
     240             : 
     241             :     /*
     242             :      * Reset some signals that are accepted by postmaster but not here
     243             :      */
     244         878 :     pqsignal(SIGCHLD, SIG_DFL);
     245             : 
     246             :     /*
     247             :      * Register timeouts needed for standby mode
     248             :      */
     249         878 :     RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, StandbyDeadLockHandler);
     250         878 :     RegisterTimeout(STANDBY_TIMEOUT, StandbyTimeoutHandler);
     251         878 :     RegisterTimeout(STANDBY_LOCK_TIMEOUT, StandbyLockTimeoutHandler);
     252             : 
     253             :     /*
     254             :      * Unblock signals (they were blocked when the postmaster forked us)
     255             :      */
     256         878 :     PG_SETMASK(&UnBlockSig);
     257             : 
     258             :     /*
     259             :      * Do what we came for.
     260             :      */
     261         878 :     StartupXLOG();
     262             : 
     263             :     /*
     264             :      * Exit normally. Exit code 0 tells postmaster that we completed recovery
     265             :      * successfully.
     266             :      */
     267         826 :     proc_exit(0);
     268             : }
     269             : 
     270             : void
     271         120 : PreRestoreCommand(void)
     272             : {
     273             :     /*
     274             :      * Set in_restore_command to tell the signal handler that we should exit
     275             :      * right away on SIGTERM. We know that we're at a safe point to do that.
     276             :      * Check if we had already received the signal, so that we don't miss a
     277             :      * shutdown request received just before this.
     278             :      */
     279         120 :     in_restore_command = true;
     280         120 :     if (shutdown_requested)
     281           0 :         proc_exit(1);
     282         120 : }
     283             : 
     284             : void
     285         120 : PostRestoreCommand(void)
     286             : {
     287         120 :     in_restore_command = false;
     288         120 : }
     289             : 
     290             : bool
     291        1078 : IsPromoteSignaled(void)
     292             : {
     293        1078 :     return promote_signaled;
     294             : }
     295             : 
     296             : void
     297          64 : ResetPromoteSignaled(void)
     298             : {
     299          64 :     promote_signaled = false;
     300          64 : }
     301             : 
     302             : /*
     303             :  * Set a flag indicating that it's time to log a progress report.
     304             :  */
     305             : void
     306          10 : startup_progress_timeout_handler(void)
     307             : {
     308          10 :     startup_progress_timer_expired = true;
     309          10 : }
     310             : 
     311             : /*
     312             :  * Set the start timestamp of the current operation and enable the timeout.
     313             :  */
     314             : void
     315         628 : begin_startup_progress_phase(void)
     316             : {
     317             :     TimestampTz fin_time;
     318             : 
     319             :     /* Feature is disabled. */
     320         628 :     if (log_startup_progress_interval == 0)
     321           0 :         return;
     322             : 
     323         628 :     disable_timeout(STARTUP_PROGRESS_TIMEOUT, false);
     324         628 :     startup_progress_timer_expired = false;
     325         628 :     startup_progress_phase_start_time = GetCurrentTimestamp();
     326         628 :     fin_time = TimestampTzPlusMilliseconds(startup_progress_phase_start_time,
     327             :                                            log_startup_progress_interval);
     328         628 :     enable_timeout_every(STARTUP_PROGRESS_TIMEOUT, fin_time,
     329             :                          log_startup_progress_interval);
     330             : }
     331             : 
     332             : /*
     333             :  * Report whether startup progress timeout has occurred. Reset the timer flag
     334             :  * if it did, set the elapsed time to the out parameters and return true,
     335             :  * otherwise return false.
     336             :  */
     337             : bool
     338      661814 : has_startup_progress_timeout_expired(long *secs, int *usecs)
     339             : {
     340             :     long        seconds;
     341             :     int         useconds;
     342             :     TimestampTz now;
     343             : 
     344             :     /* No timeout has occurred. */
     345      661814 :     if (!startup_progress_timer_expired)
     346      661814 :         return false;
     347             : 
     348             :     /* Calculate the elapsed time. */
     349           0 :     now = GetCurrentTimestamp();
     350           0 :     TimestampDifference(startup_progress_phase_start_time, now, &seconds, &useconds);
     351             : 
     352           0 :     *secs = seconds;
     353           0 :     *usecs = useconds;
     354           0 :     startup_progress_timer_expired = false;
     355             : 
     356           0 :     return true;
     357             : }

Generated by: LCOV version 1.14