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

Generated by: LCOV version 1.14