LCOV - code coverage report
Current view: top level - src/backend/access/transam - xlog.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 2202 2487 88.5 %
Date: 2026-01-11 17:16:42 Functions: 119 123 96.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * xlog.c
       4             :  *      PostgreSQL write-ahead log manager
       5             :  *
       6             :  * The Write-Ahead Log (WAL) functionality is split into several source
       7             :  * files, in addition to this one:
       8             :  *
       9             :  * xloginsert.c - Functions for constructing WAL records
      10             :  * xlogrecovery.c - WAL recovery and standby code
      11             :  * xlogreader.c - Facility for reading WAL files and parsing WAL records
      12             :  * xlogutils.c - Helper functions for WAL redo routines
      13             :  *
      14             :  * This file contains functions for coordinating database startup and
      15             :  * checkpointing, and managing the write-ahead log buffers when the
      16             :  * system is running.
      17             :  *
      18             :  * StartupXLOG() is the main entry point of the startup process.  It
      19             :  * coordinates database startup, performing WAL recovery, and the
      20             :  * transition from WAL recovery into normal operations.
      21             :  *
      22             :  * XLogInsertRecord() inserts a WAL record into the WAL buffers.  Most
      23             :  * callers should not call this directly, but use the functions in
      24             :  * xloginsert.c to construct the WAL record.  XLogFlush() can be used
      25             :  * to force the WAL to disk.
      26             :  *
      27             :  * In addition to those, there are many other functions for interrogating
      28             :  * the current system state, and for starting/stopping backups.
      29             :  *
      30             :  *
      31             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      32             :  * Portions Copyright (c) 1994, Regents of the University of California
      33             :  *
      34             :  * src/backend/access/transam/xlog.c
      35             :  *
      36             :  *-------------------------------------------------------------------------
      37             :  */
      38             : 
      39             : #include "postgres.h"
      40             : 
      41             : #include <ctype.h>
      42             : #include <math.h>
      43             : #include <time.h>
      44             : #include <fcntl.h>
      45             : #include <sys/stat.h>
      46             : #include <sys/time.h>
      47             : #include <unistd.h>
      48             : 
      49             : #include "access/clog.h"
      50             : #include "access/commit_ts.h"
      51             : #include "access/heaptoast.h"
      52             : #include "access/multixact.h"
      53             : #include "access/rewriteheap.h"
      54             : #include "access/subtrans.h"
      55             : #include "access/timeline.h"
      56             : #include "access/transam.h"
      57             : #include "access/twophase.h"
      58             : #include "access/xact.h"
      59             : #include "access/xlog_internal.h"
      60             : #include "access/xlogarchive.h"
      61             : #include "access/xloginsert.h"
      62             : #include "access/xlogreader.h"
      63             : #include "access/xlogrecovery.h"
      64             : #include "access/xlogutils.h"
      65             : #include "access/xlogwait.h"
      66             : #include "backup/basebackup.h"
      67             : #include "catalog/catversion.h"
      68             : #include "catalog/pg_control.h"
      69             : #include "catalog/pg_database.h"
      70             : #include "common/controldata_utils.h"
      71             : #include "common/file_utils.h"
      72             : #include "executor/instrument.h"
      73             : #include "miscadmin.h"
      74             : #include "pg_trace.h"
      75             : #include "pgstat.h"
      76             : #include "port/atomics.h"
      77             : #include "postmaster/bgwriter.h"
      78             : #include "postmaster/startup.h"
      79             : #include "postmaster/walsummarizer.h"
      80             : #include "postmaster/walwriter.h"
      81             : #include "replication/origin.h"
      82             : #include "replication/slot.h"
      83             : #include "replication/slotsync.h"
      84             : #include "replication/snapbuild.h"
      85             : #include "replication/walreceiver.h"
      86             : #include "replication/walsender.h"
      87             : #include "storage/bufmgr.h"
      88             : #include "storage/fd.h"
      89             : #include "storage/ipc.h"
      90             : #include "storage/large_object.h"
      91             : #include "storage/latch.h"
      92             : #include "storage/predicate.h"
      93             : #include "storage/proc.h"
      94             : #include "storage/procarray.h"
      95             : #include "storage/reinit.h"
      96             : #include "storage/spin.h"
      97             : #include "storage/sync.h"
      98             : #include "utils/guc_hooks.h"
      99             : #include "utils/guc_tables.h"
     100             : #include "utils/injection_point.h"
     101             : #include "utils/pgstat_internal.h"
     102             : #include "utils/ps_status.h"
     103             : #include "utils/relmapper.h"
     104             : #include "utils/snapmgr.h"
     105             : #include "utils/timeout.h"
     106             : #include "utils/timestamp.h"
     107             : #include "utils/varlena.h"
     108             : 
     109             : #ifdef WAL_DEBUG
     110             : #include "utils/memutils.h"
     111             : #endif
     112             : 
     113             : /* timeline ID to be used when bootstrapping */
     114             : #define BootstrapTimeLineID     1
     115             : 
     116             : /* User-settable parameters */
     117             : int         max_wal_size_mb = 1024; /* 1 GB */
     118             : int         min_wal_size_mb = 80;   /* 80 MB */
     119             : int         wal_keep_size_mb = 0;
     120             : int         XLOGbuffers = -1;
     121             : int         XLogArchiveTimeout = 0;
     122             : int         XLogArchiveMode = ARCHIVE_MODE_OFF;
     123             : char       *XLogArchiveCommand = NULL;
     124             : bool        EnableHotStandby = false;
     125             : bool        fullPageWrites = true;
     126             : bool        wal_log_hints = false;
     127             : int         wal_compression = WAL_COMPRESSION_NONE;
     128             : char       *wal_consistency_checking_string = NULL;
     129             : bool       *wal_consistency_checking = NULL;
     130             : bool        wal_init_zero = true;
     131             : bool        wal_recycle = true;
     132             : bool        log_checkpoints = true;
     133             : int         wal_sync_method = DEFAULT_WAL_SYNC_METHOD;
     134             : int         wal_level = WAL_LEVEL_REPLICA;
     135             : int         CommitDelay = 0;    /* precommit delay in microseconds */
     136             : int         CommitSiblings = 5; /* # concurrent xacts needed to sleep */
     137             : int         wal_retrieve_retry_interval = 5000;
     138             : int         max_slot_wal_keep_size_mb = -1;
     139             : int         wal_decode_buffer_size = 512 * 1024;
     140             : bool        track_wal_io_timing = false;
     141             : 
     142             : #ifdef WAL_DEBUG
     143             : bool        XLOG_DEBUG = false;
     144             : #endif
     145             : 
     146             : int         wal_segment_size = DEFAULT_XLOG_SEG_SIZE;
     147             : 
     148             : /*
     149             :  * Number of WAL insertion locks to use. A higher value allows more insertions
     150             :  * to happen concurrently, but adds some CPU overhead to flushing the WAL,
     151             :  * which needs to iterate all the locks.
     152             :  */
     153             : #define NUM_XLOGINSERT_LOCKS  8
     154             : 
     155             : /*
     156             :  * Max distance from last checkpoint, before triggering a new xlog-based
     157             :  * checkpoint.
     158             :  */
     159             : int         CheckPointSegments;
     160             : 
     161             : /* Estimated distance between checkpoints, in bytes */
     162             : static double CheckPointDistanceEstimate = 0;
     163             : static double PrevCheckPointDistance = 0;
     164             : 
     165             : /*
     166             :  * Track whether there were any deferred checks for custom resource managers
     167             :  * specified in wal_consistency_checking.
     168             :  */
     169             : static bool check_wal_consistency_checking_deferred = false;
     170             : 
     171             : /*
     172             :  * GUC support
     173             :  */
     174             : const struct config_enum_entry wal_sync_method_options[] = {
     175             :     {"fsync", WAL_SYNC_METHOD_FSYNC, false},
     176             : #ifdef HAVE_FSYNC_WRITETHROUGH
     177             :     {"fsync_writethrough", WAL_SYNC_METHOD_FSYNC_WRITETHROUGH, false},
     178             : #endif
     179             :     {"fdatasync", WAL_SYNC_METHOD_FDATASYNC, false},
     180             : #ifdef O_SYNC
     181             :     {"open_sync", WAL_SYNC_METHOD_OPEN, false},
     182             : #endif
     183             : #ifdef O_DSYNC
     184             :     {"open_datasync", WAL_SYNC_METHOD_OPEN_DSYNC, false},
     185             : #endif
     186             :     {NULL, 0, false}
     187             : };
     188             : 
     189             : 
     190             : /*
     191             :  * Although only "on", "off", and "always" are documented,
     192             :  * we accept all the likely variants of "on" and "off".
     193             :  */
     194             : const struct config_enum_entry archive_mode_options[] = {
     195             :     {"always", ARCHIVE_MODE_ALWAYS, false},
     196             :     {"on", ARCHIVE_MODE_ON, false},
     197             :     {"off", ARCHIVE_MODE_OFF, false},
     198             :     {"true", ARCHIVE_MODE_ON, true},
     199             :     {"false", ARCHIVE_MODE_OFF, true},
     200             :     {"yes", ARCHIVE_MODE_ON, true},
     201             :     {"no", ARCHIVE_MODE_OFF, true},
     202             :     {"1", ARCHIVE_MODE_ON, true},
     203             :     {"0", ARCHIVE_MODE_OFF, true},
     204             :     {NULL, 0, false}
     205             : };
     206             : 
     207             : /*
     208             :  * Statistics for current checkpoint are collected in this global struct.
     209             :  * Because only the checkpointer or a stand-alone backend can perform
     210             :  * checkpoints, this will be unused in normal backends.
     211             :  */
     212             : CheckpointStatsData CheckpointStats;
     213             : 
     214             : /*
     215             :  * During recovery, lastFullPageWrites keeps track of full_page_writes that
     216             :  * the replayed WAL records indicate. It's initialized with full_page_writes
     217             :  * that the recovery starting checkpoint record indicates, and then updated
     218             :  * each time XLOG_FPW_CHANGE record is replayed.
     219             :  */
     220             : static bool lastFullPageWrites;
     221             : 
     222             : /*
     223             :  * Local copy of the state tracked by SharedRecoveryState in shared memory,
     224             :  * It is false if SharedRecoveryState is RECOVERY_STATE_DONE.  True actually
     225             :  * means "not known, need to check the shared state".
     226             :  */
     227             : static bool LocalRecoveryInProgress = true;
     228             : 
     229             : /*
     230             :  * Local state for XLogInsertAllowed():
     231             :  *      1: unconditionally allowed to insert XLOG
     232             :  *      0: unconditionally not allowed to insert XLOG
     233             :  *      -1: must check RecoveryInProgress(); disallow until it is false
     234             :  * Most processes start with -1 and transition to 1 after seeing that recovery
     235             :  * is not in progress.  But we can also force the value for special cases.
     236             :  * The coding in XLogInsertAllowed() depends on the first two of these states
     237             :  * being numerically the same as bool true and false.
     238             :  */
     239             : static int  LocalXLogInsertAllowed = -1;
     240             : 
     241             : /*
     242             :  * ProcLastRecPtr points to the start of the last XLOG record inserted by the
     243             :  * current backend.  It is updated for all inserts.  XactLastRecEnd points to
     244             :  * end+1 of the last record, and is reset when we end a top-level transaction,
     245             :  * or start a new one; so it can be used to tell if the current transaction has
     246             :  * created any XLOG records.
     247             :  *
     248             :  * While in parallel mode, this may not be fully up to date.  When committing,
     249             :  * a transaction can assume this covers all xlog records written either by the
     250             :  * user backend or by any parallel worker which was present at any point during
     251             :  * the transaction.  But when aborting, or when still in parallel mode, other
     252             :  * parallel backends may have written WAL records at later LSNs than the value
     253             :  * stored here.  The parallel leader advances its own copy, when necessary,
     254             :  * in WaitForParallelWorkersToFinish.
     255             :  */
     256             : XLogRecPtr  ProcLastRecPtr = InvalidXLogRecPtr;
     257             : XLogRecPtr  XactLastRecEnd = InvalidXLogRecPtr;
     258             : XLogRecPtr  XactLastCommitEnd = InvalidXLogRecPtr;
     259             : 
     260             : /*
     261             :  * RedoRecPtr is this backend's local copy of the REDO record pointer
     262             :  * (which is almost but not quite the same as a pointer to the most recent
     263             :  * CHECKPOINT record).  We update this from the shared-memory copy,
     264             :  * XLogCtl->Insert.RedoRecPtr, whenever we can safely do so (ie, when we
     265             :  * hold an insertion lock).  See XLogInsertRecord for details.  We are also
     266             :  * allowed to update from XLogCtl->RedoRecPtr if we hold the info_lck;
     267             :  * see GetRedoRecPtr.
     268             :  *
     269             :  * NB: Code that uses this variable must be prepared not only for the
     270             :  * possibility that it may be arbitrarily out of date, but also for the
     271             :  * possibility that it might be set to InvalidXLogRecPtr. We used to
     272             :  * initialize it as a side effect of the first call to RecoveryInProgress(),
     273             :  * which meant that most code that might use it could assume that it had a
     274             :  * real if perhaps stale value. That's no longer the case.
     275             :  */
     276             : static XLogRecPtr RedoRecPtr;
     277             : 
     278             : /*
     279             :  * doPageWrites is this backend's local copy of (fullPageWrites ||
     280             :  * runningBackups > 0).  It is used together with RedoRecPtr to decide whether
     281             :  * a full-page image of a page need to be taken.
     282             :  *
     283             :  * NB: Initially this is false, and there's no guarantee that it will be
     284             :  * initialized to any other value before it is first used. Any code that
     285             :  * makes use of it must recheck the value after obtaining a WALInsertLock,
     286             :  * and respond appropriately if it turns out that the previous value wasn't
     287             :  * accurate.
     288             :  */
     289             : static bool doPageWrites;
     290             : 
     291             : /*----------
     292             :  * Shared-memory data structures for XLOG control
     293             :  *
     294             :  * LogwrtRqst indicates a byte position that we need to write and/or fsync
     295             :  * the log up to (all records before that point must be written or fsynced).
     296             :  * The positions already written/fsynced are maintained in logWriteResult
     297             :  * and logFlushResult using atomic access.
     298             :  * In addition to the shared variable, each backend has a private copy of
     299             :  * both in LogwrtResult, which is updated when convenient.
     300             :  *
     301             :  * The request bookkeeping is simpler: there is a shared XLogCtl->LogwrtRqst
     302             :  * (protected by info_lck), but we don't need to cache any copies of it.
     303             :  *
     304             :  * info_lck is only held long enough to read/update the protected variables,
     305             :  * so it's a plain spinlock.  The other locks are held longer (potentially
     306             :  * over I/O operations), so we use LWLocks for them.  These locks are:
     307             :  *
     308             :  * WALBufMappingLock: must be held to replace a page in the WAL buffer cache.
     309             :  * It is only held while initializing and changing the mapping.  If the
     310             :  * contents of the buffer being replaced haven't been written yet, the mapping
     311             :  * lock is released while the write is done, and reacquired afterwards.
     312             :  *
     313             :  * WALWriteLock: must be held to write WAL buffers to disk (XLogWrite or
     314             :  * XLogFlush).
     315             :  *
     316             :  * ControlFileLock: must be held to read/update control file or create
     317             :  * new log file.
     318             :  *
     319             :  *----------
     320             :  */
     321             : 
     322             : typedef struct XLogwrtRqst
     323             : {
     324             :     XLogRecPtr  Write;          /* last byte + 1 to write out */
     325             :     XLogRecPtr  Flush;          /* last byte + 1 to flush */
     326             : } XLogwrtRqst;
     327             : 
     328             : typedef struct XLogwrtResult
     329             : {
     330             :     XLogRecPtr  Write;          /* last byte + 1 written out */
     331             :     XLogRecPtr  Flush;          /* last byte + 1 flushed */
     332             : } XLogwrtResult;
     333             : 
     334             : /*
     335             :  * Inserting to WAL is protected by a small fixed number of WAL insertion
     336             :  * locks. To insert to the WAL, you must hold one of the locks - it doesn't
     337             :  * matter which one. To lock out other concurrent insertions, you must hold
     338             :  * of them. Each WAL insertion lock consists of a lightweight lock, plus an
     339             :  * indicator of how far the insertion has progressed (insertingAt).
     340             :  *
     341             :  * The insertingAt values are read when a process wants to flush WAL from
     342             :  * the in-memory buffers to disk, to check that all the insertions to the
     343             :  * region the process is about to write out have finished. You could simply
     344             :  * wait for all currently in-progress insertions to finish, but the
     345             :  * insertingAt indicator allows you to ignore insertions to later in the WAL,
     346             :  * so that you only wait for the insertions that are modifying the buffers
     347             :  * you're about to write out.
     348             :  *
     349             :  * This isn't just an optimization. If all the WAL buffers are dirty, an
     350             :  * inserter that's holding a WAL insert lock might need to evict an old WAL
     351             :  * buffer, which requires flushing the WAL. If it's possible for an inserter
     352             :  * to block on another inserter unnecessarily, deadlock can arise when two
     353             :  * inserters holding a WAL insert lock wait for each other to finish their
     354             :  * insertion.
     355             :  *
     356             :  * Small WAL records that don't cross a page boundary never update the value,
     357             :  * the WAL record is just copied to the page and the lock is released. But
     358             :  * to avoid the deadlock-scenario explained above, the indicator is always
     359             :  * updated before sleeping while holding an insertion lock.
     360             :  *
     361             :  * lastImportantAt contains the LSN of the last important WAL record inserted
     362             :  * using a given lock. This value is used to detect if there has been
     363             :  * important WAL activity since the last time some action, like a checkpoint,
     364             :  * was performed - allowing to not repeat the action if not. The LSN is
     365             :  * updated for all insertions, unless the XLOG_MARK_UNIMPORTANT flag was
     366             :  * set. lastImportantAt is never cleared, only overwritten by the LSN of newer
     367             :  * records.  Tracking the WAL activity directly in WALInsertLock has the
     368             :  * advantage of not needing any additional locks to update the value.
     369             :  */
     370             : typedef struct
     371             : {
     372             :     LWLock      lock;
     373             :     pg_atomic_uint64 insertingAt;
     374             :     XLogRecPtr  lastImportantAt;
     375             : } WALInsertLock;
     376             : 
     377             : /*
     378             :  * All the WAL insertion locks are allocated as an array in shared memory. We
     379             :  * force the array stride to be a power of 2, which saves a few cycles in
     380             :  * indexing, but more importantly also ensures that individual slots don't
     381             :  * cross cache line boundaries. (Of course, we have to also ensure that the
     382             :  * array start address is suitably aligned.)
     383             :  */
     384             : typedef union WALInsertLockPadded
     385             : {
     386             :     WALInsertLock l;
     387             :     char        pad[PG_CACHE_LINE_SIZE];
     388             : } WALInsertLockPadded;
     389             : 
     390             : /*
     391             :  * Session status of running backup, used for sanity checks in SQL-callable
     392             :  * functions to start and stop backups.
     393             :  */
     394             : static SessionBackupState sessionBackupState = SESSION_BACKUP_NONE;
     395             : 
     396             : /*
     397             :  * Shared state data for WAL insertion.
     398             :  */
     399             : typedef struct XLogCtlInsert
     400             : {
     401             :     slock_t     insertpos_lck;  /* protects CurrBytePos and PrevBytePos */
     402             : 
     403             :     /*
     404             :      * CurrBytePos is the end of reserved WAL. The next record will be
     405             :      * inserted at that position. PrevBytePos is the start position of the
     406             :      * previously inserted (or rather, reserved) record - it is copied to the
     407             :      * prev-link of the next record. These are stored as "usable byte
     408             :      * positions" rather than XLogRecPtrs (see XLogBytePosToRecPtr()).
     409             :      */
     410             :     uint64      CurrBytePos;
     411             :     uint64      PrevBytePos;
     412             : 
     413             :     /*
     414             :      * Make sure the above heavily-contended spinlock and byte positions are
     415             :      * on their own cache line. In particular, the RedoRecPtr and full page
     416             :      * write variables below should be on a different cache line. They are
     417             :      * read on every WAL insertion, but updated rarely, and we don't want
     418             :      * those reads to steal the cache line containing Curr/PrevBytePos.
     419             :      */
     420             :     char        pad[PG_CACHE_LINE_SIZE];
     421             : 
     422             :     /*
     423             :      * fullPageWrites is the authoritative value used by all backends to
     424             :      * determine whether to write full-page image to WAL. This shared value,
     425             :      * instead of the process-local fullPageWrites, is required because, when
     426             :      * full_page_writes is changed by SIGHUP, we must WAL-log it before it
     427             :      * actually affects WAL-logging by backends.  Checkpointer sets at startup
     428             :      * or after SIGHUP.
     429             :      *
     430             :      * To read these fields, you must hold an insertion lock. To modify them,
     431             :      * you must hold ALL the locks.
     432             :      */
     433             :     XLogRecPtr  RedoRecPtr;     /* current redo point for insertions */
     434             :     bool        fullPageWrites;
     435             : 
     436             :     /*
     437             :      * runningBackups is a counter indicating the number of backups currently
     438             :      * in progress. lastBackupStart is the latest checkpoint redo location
     439             :      * used as a starting point for an online backup.
     440             :      */
     441             :     int         runningBackups;
     442             :     XLogRecPtr  lastBackupStart;
     443             : 
     444             :     /*
     445             :      * WAL insertion locks.
     446             :      */
     447             :     WALInsertLockPadded *WALInsertLocks;
     448             : } XLogCtlInsert;
     449             : 
     450             : /*
     451             :  * Total shared-memory state for XLOG.
     452             :  */
     453             : typedef struct XLogCtlData
     454             : {
     455             :     XLogCtlInsert Insert;
     456             : 
     457             :     /* Protected by info_lck: */
     458             :     XLogwrtRqst LogwrtRqst;
     459             :     XLogRecPtr  RedoRecPtr;     /* a recent copy of Insert->RedoRecPtr */
     460             :     XLogRecPtr  asyncXactLSN;   /* LSN of newest async commit/abort */
     461             :     XLogRecPtr  replicationSlotMinLSN;  /* oldest LSN needed by any slot */
     462             : 
     463             :     XLogSegNo   lastRemovedSegNo;   /* latest removed/recycled XLOG segment */
     464             : 
     465             :     /* Fake LSN counter, for unlogged relations. */
     466             :     pg_atomic_uint64 unloggedLSN;
     467             : 
     468             :     /* Time and LSN of last xlog segment switch. Protected by WALWriteLock. */
     469             :     pg_time_t   lastSegSwitchTime;
     470             :     XLogRecPtr  lastSegSwitchLSN;
     471             : 
     472             :     /* These are accessed using atomics -- info_lck not needed */
     473             :     pg_atomic_uint64 logInsertResult;   /* last byte + 1 inserted to buffers */
     474             :     pg_atomic_uint64 logWriteResult;    /* last byte + 1 written out */
     475             :     pg_atomic_uint64 logFlushResult;    /* last byte + 1 flushed */
     476             : 
     477             :     /*
     478             :      * Latest initialized page in the cache (last byte position + 1).
     479             :      *
     480             :      * To change the identity of a buffer (and InitializedUpTo), you need to
     481             :      * hold WALBufMappingLock.  To change the identity of a buffer that's
     482             :      * still dirty, the old page needs to be written out first, and for that
     483             :      * you need WALWriteLock, and you need to ensure that there are no
     484             :      * in-progress insertions to the page by calling
     485             :      * WaitXLogInsertionsToFinish().
     486             :      */
     487             :     XLogRecPtr  InitializedUpTo;
     488             : 
     489             :     /*
     490             :      * These values do not change after startup, although the pointed-to pages
     491             :      * and xlblocks values certainly do.  xlblocks values are protected by
     492             :      * WALBufMappingLock.
     493             :      */
     494             :     char       *pages;          /* buffers for unwritten XLOG pages */
     495             :     pg_atomic_uint64 *xlblocks; /* 1st byte ptr-s + XLOG_BLCKSZ */
     496             :     int         XLogCacheBlck;  /* highest allocated xlog buffer index */
     497             : 
     498             :     /*
     499             :      * InsertTimeLineID is the timeline into which new WAL is being inserted
     500             :      * and flushed. It is zero during recovery, and does not change once set.
     501             :      *
     502             :      * If we create a new timeline when the system was started up,
     503             :      * PrevTimeLineID is the old timeline's ID that we forked off from.
     504             :      * Otherwise it's equal to InsertTimeLineID.
     505             :      *
     506             :      * We set these fields while holding info_lck. Most that reads these
     507             :      * values knows that recovery is no longer in progress and so can safely
     508             :      * read the value without a lock, but code that could be run either during
     509             :      * or after recovery can take info_lck while reading these values.
     510             :      */
     511             :     TimeLineID  InsertTimeLineID;
     512             :     TimeLineID  PrevTimeLineID;
     513             : 
     514             :     /*
     515             :      * SharedRecoveryState indicates if we're still in crash or archive
     516             :      * recovery.  Protected by info_lck.
     517             :      */
     518             :     RecoveryState SharedRecoveryState;
     519             : 
     520             :     /*
     521             :      * InstallXLogFileSegmentActive indicates whether the checkpointer should
     522             :      * arrange for future segments by recycling and/or PreallocXlogFiles().
     523             :      * Protected by ControlFileLock.  Only the startup process changes it.  If
     524             :      * true, anyone can use InstallXLogFileSegment().  If false, the startup
     525             :      * process owns the exclusive right to install segments, by reading from
     526             :      * the archive and possibly replacing existing files.
     527             :      */
     528             :     bool        InstallXLogFileSegmentActive;
     529             : 
     530             :     /*
     531             :      * WalWriterSleeping indicates whether the WAL writer is currently in
     532             :      * low-power mode (and hence should be nudged if an async commit occurs).
     533             :      * Protected by info_lck.
     534             :      */
     535             :     bool        WalWriterSleeping;
     536             : 
     537             :     /*
     538             :      * During recovery, we keep a copy of the latest checkpoint record here.
     539             :      * lastCheckPointRecPtr points to start of checkpoint record and
     540             :      * lastCheckPointEndPtr points to end+1 of checkpoint record.  Used by the
     541             :      * checkpointer when it wants to create a restartpoint.
     542             :      *
     543             :      * Protected by info_lck.
     544             :      */
     545             :     XLogRecPtr  lastCheckPointRecPtr;
     546             :     XLogRecPtr  lastCheckPointEndPtr;
     547             :     CheckPoint  lastCheckPoint;
     548             : 
     549             :     /*
     550             :      * lastFpwDisableRecPtr points to the start of the last replayed
     551             :      * XLOG_FPW_CHANGE record that instructs full_page_writes is disabled.
     552             :      */
     553             :     XLogRecPtr  lastFpwDisableRecPtr;
     554             : 
     555             :     slock_t     info_lck;       /* locks shared variables shown above */
     556             : } XLogCtlData;
     557             : 
     558             : /*
     559             :  * Classification of XLogInsertRecord operations.
     560             :  */
     561             : typedef enum
     562             : {
     563             :     WALINSERT_NORMAL,
     564             :     WALINSERT_SPECIAL_SWITCH,
     565             :     WALINSERT_SPECIAL_CHECKPOINT
     566             : } WalInsertClass;
     567             : 
     568             : static XLogCtlData *XLogCtl = NULL;
     569             : 
     570             : /* a private copy of XLogCtl->Insert.WALInsertLocks, for convenience */
     571             : static WALInsertLockPadded *WALInsertLocks = NULL;
     572             : 
     573             : /*
     574             :  * We maintain an image of pg_control in shared memory.
     575             :  */
     576             : static ControlFileData *ControlFile = NULL;
     577             : 
     578             : /*
     579             :  * Calculate the amount of space left on the page after 'endptr'. Beware
     580             :  * multiple evaluation!
     581             :  */
     582             : #define INSERT_FREESPACE(endptr)    \
     583             :     (((endptr) % XLOG_BLCKSZ == 0) ? 0 : (XLOG_BLCKSZ - (endptr) % XLOG_BLCKSZ))
     584             : 
     585             : /* Macro to advance to next buffer index. */
     586             : #define NextBufIdx(idx)     \
     587             :         (((idx) == XLogCtl->XLogCacheBlck) ? 0 : ((idx) + 1))
     588             : 
     589             : /*
     590             :  * XLogRecPtrToBufIdx returns the index of the WAL buffer that holds, or
     591             :  * would hold if it was in cache, the page containing 'recptr'.
     592             :  */
     593             : #define XLogRecPtrToBufIdx(recptr)  \
     594             :     (((recptr) / XLOG_BLCKSZ) % (XLogCtl->XLogCacheBlck + 1))
     595             : 
     596             : /*
     597             :  * These are the number of bytes in a WAL page usable for WAL data.
     598             :  */
     599             : #define UsableBytesInPage (XLOG_BLCKSZ - SizeOfXLogShortPHD)
     600             : 
     601             : /*
     602             :  * Convert values of GUCs measured in megabytes to equiv. segment count.
     603             :  * Rounds down.
     604             :  */
     605             : #define ConvertToXSegs(x, segsize)  XLogMBVarToSegs((x), (segsize))
     606             : 
     607             : /* The number of bytes in a WAL segment usable for WAL data. */
     608             : static int  UsableBytesInSegment;
     609             : 
     610             : /*
     611             :  * Private, possibly out-of-date copy of shared LogwrtResult.
     612             :  * See discussion above.
     613             :  */
     614             : static XLogwrtResult LogwrtResult = {0, 0};
     615             : 
     616             : /*
     617             :  * Update local copy of shared XLogCtl->log{Write,Flush}Result
     618             :  *
     619             :  * It's critical that Flush always trails Write, so the order of the reads is
     620             :  * important, as is the barrier.  See also XLogWrite.
     621             :  */
     622             : #define RefreshXLogWriteResult(_target) \
     623             :     do { \
     624             :         _target.Flush = pg_atomic_read_u64(&XLogCtl->logFlushResult); \
     625             :         pg_read_barrier(); \
     626             :         _target.Write = pg_atomic_read_u64(&XLogCtl->logWriteResult); \
     627             :     } while (0)
     628             : 
     629             : /*
     630             :  * openLogFile is -1 or a kernel FD for an open log file segment.
     631             :  * openLogSegNo identifies the segment, and openLogTLI the corresponding TLI.
     632             :  * These variables are only used to write the XLOG, and so will normally refer
     633             :  * to the active segment.
     634             :  *
     635             :  * Note: call Reserve/ReleaseExternalFD to track consumption of this FD.
     636             :  */
     637             : static int  openLogFile = -1;
     638             : static XLogSegNo openLogSegNo = 0;
     639             : static TimeLineID openLogTLI = 0;
     640             : 
     641             : /*
     642             :  * Local copies of equivalent fields in the control file.  When running
     643             :  * crash recovery, LocalMinRecoveryPoint is set to InvalidXLogRecPtr as we
     644             :  * expect to replay all the WAL available, and updateMinRecoveryPoint is
     645             :  * switched to false to prevent any updates while replaying records.
     646             :  * Those values are kept consistent as long as crash recovery runs.
     647             :  */
     648             : static XLogRecPtr LocalMinRecoveryPoint;
     649             : static TimeLineID LocalMinRecoveryPointTLI;
     650             : static bool updateMinRecoveryPoint = true;
     651             : 
     652             : /* For WALInsertLockAcquire/Release functions */
     653             : static int  MyLockNo = 0;
     654             : static bool holdingAllLocks = false;
     655             : 
     656             : #ifdef WAL_DEBUG
     657             : static MemoryContext walDebugCxt = NULL;
     658             : #endif
     659             : 
     660             : static void CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI,
     661             :                                         XLogRecPtr EndOfLog,
     662             :                                         TimeLineID newTLI);
     663             : static void CheckRequiredParameterValues(void);
     664             : static void XLogReportParameters(void);
     665             : static int  LocalSetXLogInsertAllowed(void);
     666             : static void CreateEndOfRecoveryRecord(void);
     667             : static XLogRecPtr CreateOverwriteContrecordRecord(XLogRecPtr aborted_lsn,
     668             :                                                   XLogRecPtr pagePtr,
     669             :                                                   TimeLineID newTLI);
     670             : static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
     671             : static void KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo);
     672             : static XLogRecPtr XLogGetReplicationSlotMinimumLSN(void);
     673             : 
     674             : static void AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli,
     675             :                                   bool opportunistic);
     676             : static void XLogWrite(XLogwrtRqst WriteRqst, TimeLineID tli, bool flexible);
     677             : static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
     678             :                                    bool find_free, XLogSegNo max_segno,
     679             :                                    TimeLineID tli);
     680             : static void XLogFileClose(void);
     681             : static void PreallocXlogFiles(XLogRecPtr endptr, TimeLineID tli);
     682             : static void RemoveTempXlogFiles(void);
     683             : static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr,
     684             :                                XLogRecPtr endptr, TimeLineID insertTLI);
     685             : static void RemoveXlogFile(const struct dirent *segment_de,
     686             :                            XLogSegNo recycleSegNo, XLogSegNo *endlogSegNo,
     687             :                            TimeLineID insertTLI);
     688             : static void UpdateLastRemovedPtr(char *filename);
     689             : static void ValidateXLOGDirectoryStructure(void);
     690             : static void CleanupBackupHistory(void);
     691             : static void UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force);
     692             : static bool PerformRecoveryXLogAction(void);
     693             : static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
     694             : static void WriteControlFile(void);
     695             : static void ReadControlFile(void);
     696             : static void UpdateControlFile(void);
     697             : static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
     698             : 
     699             : static int  get_sync_bit(int method);
     700             : 
     701             : static void CopyXLogRecordToWAL(int write_len, bool isLogSwitch,
     702             :                                 XLogRecData *rdata,
     703             :                                 XLogRecPtr StartPos, XLogRecPtr EndPos,
     704             :                                 TimeLineID tli);
     705             : static void ReserveXLogInsertLocation(int size, XLogRecPtr *StartPos,
     706             :                                       XLogRecPtr *EndPos, XLogRecPtr *PrevPtr);
     707             : static bool ReserveXLogSwitch(XLogRecPtr *StartPos, XLogRecPtr *EndPos,
     708             :                               XLogRecPtr *PrevPtr);
     709             : static XLogRecPtr WaitXLogInsertionsToFinish(XLogRecPtr upto);
     710             : static char *GetXLogBuffer(XLogRecPtr ptr, TimeLineID tli);
     711             : static XLogRecPtr XLogBytePosToRecPtr(uint64 bytepos);
     712             : static XLogRecPtr XLogBytePosToEndRecPtr(uint64 bytepos);
     713             : static uint64 XLogRecPtrToBytePos(XLogRecPtr ptr);
     714             : 
     715             : static void WALInsertLockAcquire(void);
     716             : static void WALInsertLockAcquireExclusive(void);
     717             : static void WALInsertLockRelease(void);
     718             : static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt);
     719             : 
     720             : /*
     721             :  * Insert an XLOG record represented by an already-constructed chain of data
     722             :  * chunks.  This is a low-level routine; to construct the WAL record header
     723             :  * and data, use the higher-level routines in xloginsert.c.
     724             :  *
     725             :  * If 'fpw_lsn' is valid, it is the oldest LSN among the pages that this
     726             :  * WAL record applies to, that were not included in the record as full page
     727             :  * images.  If fpw_lsn <= RedoRecPtr, the function does not perform the
     728             :  * insertion and returns InvalidXLogRecPtr.  The caller can then recalculate
     729             :  * which pages need a full-page image, and retry.  If fpw_lsn is invalid, the
     730             :  * record is always inserted.
     731             :  *
     732             :  * 'flags' gives more in-depth control on the record being inserted. See
     733             :  * XLogSetRecordFlags() for details.
     734             :  *
     735             :  * 'topxid_included' tells whether the top-transaction id is logged along with
     736             :  * current subtransaction. See XLogRecordAssemble().
     737             :  *
     738             :  * The first XLogRecData in the chain must be for the record header, and its
     739             :  * data must be MAXALIGNed.  XLogInsertRecord fills in the xl_prev and
     740             :  * xl_crc fields in the header, the rest of the header must already be filled
     741             :  * by the caller.
     742             :  *
     743             :  * Returns XLOG pointer to end of record (beginning of next record).
     744             :  * This can be used as LSN for data pages affected by the logged action.
     745             :  * (LSN is the XLOG point up to which the XLOG must be flushed to disk
     746             :  * before the data page can be written out.  This implements the basic
     747             :  * WAL rule "write the log before the data".)
     748             :  */
     749             : XLogRecPtr
     750    30770350 : XLogInsertRecord(XLogRecData *rdata,
     751             :                  XLogRecPtr fpw_lsn,
     752             :                  uint8 flags,
     753             :                  int num_fpi,
     754             :                  uint64 fpi_bytes,
     755             :                  bool topxid_included)
     756             : {
     757    30770350 :     XLogCtlInsert *Insert = &XLogCtl->Insert;
     758             :     pg_crc32c   rdata_crc;
     759             :     bool        inserted;
     760    30770350 :     XLogRecord *rechdr = (XLogRecord *) rdata->data;
     761    30770350 :     uint8       info = rechdr->xl_info & ~XLR_INFO_MASK;
     762    30770350 :     WalInsertClass class = WALINSERT_NORMAL;
     763             :     XLogRecPtr  StartPos;
     764             :     XLogRecPtr  EndPos;
     765    30770350 :     bool        prevDoPageWrites = doPageWrites;
     766             :     TimeLineID  insertTLI;
     767             : 
     768             :     /* Does this record type require special handling? */
     769    30770350 :     if (unlikely(rechdr->xl_rmid == RM_XLOG_ID))
     770             :     {
     771      462000 :         if (info == XLOG_SWITCH)
     772        1576 :             class = WALINSERT_SPECIAL_SWITCH;
     773      460424 :         else if (info == XLOG_CHECKPOINT_REDO)
     774        1852 :             class = WALINSERT_SPECIAL_CHECKPOINT;
     775             :     }
     776             : 
     777             :     /* we assume that all of the record header is in the first chunk */
     778             :     Assert(rdata->len >= SizeOfXLogRecord);
     779             : 
     780             :     /* cross-check on whether we should be here or not */
     781    30770350 :     if (!XLogInsertAllowed())
     782           0 :         elog(ERROR, "cannot make new WAL entries during recovery");
     783             : 
     784             :     /*
     785             :      * Given that we're not in recovery, InsertTimeLineID is set and can't
     786             :      * change, so we can read it without a lock.
     787             :      */
     788    30770350 :     insertTLI = XLogCtl->InsertTimeLineID;
     789             : 
     790             :     /*----------
     791             :      *
     792             :      * We have now done all the preparatory work we can without holding a
     793             :      * lock or modifying shared state. From here on, inserting the new WAL
     794             :      * record to the shared WAL buffer cache is a two-step process:
     795             :      *
     796             :      * 1. Reserve the right amount of space from the WAL. The current head of
     797             :      *    reserved space is kept in Insert->CurrBytePos, and is protected by
     798             :      *    insertpos_lck.
     799             :      *
     800             :      * 2. Copy the record to the reserved WAL space. This involves finding the
     801             :      *    correct WAL buffer containing the reserved space, and copying the
     802             :      *    record in place. This can be done concurrently in multiple processes.
     803             :      *
     804             :      * To keep track of which insertions are still in-progress, each concurrent
     805             :      * inserter acquires an insertion lock. In addition to just indicating that
     806             :      * an insertion is in progress, the lock tells others how far the inserter
     807             :      * has progressed. There is a small fixed number of insertion locks,
     808             :      * determined by NUM_XLOGINSERT_LOCKS. When an inserter crosses a page
     809             :      * boundary, it updates the value stored in the lock to the how far it has
     810             :      * inserted, to allow the previous buffer to be flushed.
     811             :      *
     812             :      * Holding onto an insertion lock also protects RedoRecPtr and
     813             :      * fullPageWrites from changing until the insertion is finished.
     814             :      *
     815             :      * Step 2 can usually be done completely in parallel. If the required WAL
     816             :      * page is not initialized yet, you have to grab WALBufMappingLock to
     817             :      * initialize it, but the WAL writer tries to do that ahead of insertions
     818             :      * to avoid that from happening in the critical path.
     819             :      *
     820             :      *----------
     821             :      */
     822    30770350 :     START_CRIT_SECTION();
     823             : 
     824    30770350 :     if (likely(class == WALINSERT_NORMAL))
     825             :     {
     826    30766922 :         WALInsertLockAcquire();
     827             : 
     828             :         /*
     829             :          * Check to see if my copy of RedoRecPtr is out of date. If so, may
     830             :          * have to go back and have the caller recompute everything. This can
     831             :          * only happen just after a checkpoint, so it's better to be slow in
     832             :          * this case and fast otherwise.
     833             :          *
     834             :          * Also check to see if fullPageWrites was just turned on or there's a
     835             :          * running backup (which forces full-page writes); if we weren't
     836             :          * already doing full-page writes then go back and recompute.
     837             :          *
     838             :          * If we aren't doing full-page writes then RedoRecPtr doesn't
     839             :          * actually affect the contents of the XLOG record, so we'll update
     840             :          * our local copy but not force a recomputation.  (If doPageWrites was
     841             :          * just turned off, we could recompute the record without full pages,
     842             :          * but we choose not to bother.)
     843             :          */
     844    30766922 :         if (RedoRecPtr != Insert->RedoRecPtr)
     845             :         {
     846             :             Assert(RedoRecPtr < Insert->RedoRecPtr);
     847       14532 :             RedoRecPtr = Insert->RedoRecPtr;
     848             :         }
     849    30766922 :         doPageWrites = (Insert->fullPageWrites || Insert->runningBackups > 0);
     850             : 
     851    30766922 :         if (doPageWrites &&
     852    30269794 :             (!prevDoPageWrites ||
     853    27791954 :              (XLogRecPtrIsValid(fpw_lsn) && fpw_lsn <= RedoRecPtr)))
     854             :         {
     855             :             /*
     856             :              * Oops, some buffer now needs to be backed up that the caller
     857             :              * didn't back up.  Start over.
     858             :              */
     859       15974 :             WALInsertLockRelease();
     860       15974 :             END_CRIT_SECTION();
     861       15974 :             return InvalidXLogRecPtr;
     862             :         }
     863             : 
     864             :         /*
     865             :          * Reserve space for the record in the WAL. This also sets the xl_prev
     866             :          * pointer.
     867             :          */
     868    30750948 :         ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
     869             :                                   &rechdr->xl_prev);
     870             : 
     871             :         /* Normal records are always inserted. */
     872    30750948 :         inserted = true;
     873             :     }
     874        3428 :     else if (class == WALINSERT_SPECIAL_SWITCH)
     875             :     {
     876             :         /*
     877             :          * In order to insert an XLOG_SWITCH record, we need to hold all of
     878             :          * the WAL insertion locks, not just one, so that no one else can
     879             :          * begin inserting a record until we've figured out how much space
     880             :          * remains in the current WAL segment and claimed all of it.
     881             :          *
     882             :          * Nonetheless, this case is simpler than the normal cases handled
     883             :          * below, which must check for changes in doPageWrites and RedoRecPtr.
     884             :          * Those checks are only needed for records that can contain buffer
     885             :          * references, and an XLOG_SWITCH record never does.
     886             :          */
     887             :         Assert(!XLogRecPtrIsValid(fpw_lsn));
     888        1576 :         WALInsertLockAcquireExclusive();
     889        1576 :         inserted = ReserveXLogSwitch(&StartPos, &EndPos, &rechdr->xl_prev);
     890             :     }
     891             :     else
     892             :     {
     893             :         Assert(class == WALINSERT_SPECIAL_CHECKPOINT);
     894             : 
     895             :         /*
     896             :          * We need to update both the local and shared copies of RedoRecPtr,
     897             :          * which means that we need to hold all the WAL insertion locks.
     898             :          * However, there can't be any buffer references, so as above, we need
     899             :          * not check RedoRecPtr before inserting the record; we just need to
     900             :          * update it afterwards.
     901             :          */
     902             :         Assert(!XLogRecPtrIsValid(fpw_lsn));
     903        1852 :         WALInsertLockAcquireExclusive();
     904        1852 :         ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
     905             :                                   &rechdr->xl_prev);
     906        1852 :         RedoRecPtr = Insert->RedoRecPtr = StartPos;
     907        1852 :         inserted = true;
     908             :     }
     909             : 
     910    30754376 :     if (inserted)
     911             :     {
     912             :         /*
     913             :          * Now that xl_prev has been filled in, calculate CRC of the record
     914             :          * header.
     915             :          */
     916    30754264 :         rdata_crc = rechdr->xl_crc;
     917    30754264 :         COMP_CRC32C(rdata_crc, rechdr, offsetof(XLogRecord, xl_crc));
     918    30754264 :         FIN_CRC32C(rdata_crc);
     919    30754264 :         rechdr->xl_crc = rdata_crc;
     920             : 
     921             :         /*
     922             :          * All the record data, including the header, is now ready to be
     923             :          * inserted. Copy the record in the space reserved.
     924             :          */
     925    30754264 :         CopyXLogRecordToWAL(rechdr->xl_tot_len,
     926             :                             class == WALINSERT_SPECIAL_SWITCH, rdata,
     927             :                             StartPos, EndPos, insertTLI);
     928             : 
     929             :         /*
     930             :          * Unless record is flagged as not important, update LSN of last
     931             :          * important record in the current slot. When holding all locks, just
     932             :          * update the first one.
     933             :          */
     934    30754264 :         if ((flags & XLOG_MARK_UNIMPORTANT) == 0)
     935             :         {
     936    30512640 :             int         lockno = holdingAllLocks ? 0 : MyLockNo;
     937             : 
     938    30512640 :             WALInsertLocks[lockno].l.lastImportantAt = StartPos;
     939             :         }
     940             :     }
     941             :     else
     942             :     {
     943             :         /*
     944             :          * This was an xlog-switch record, but the current insert location was
     945             :          * already exactly at the beginning of a segment, so there was no need
     946             :          * to do anything.
     947             :          */
     948             :     }
     949             : 
     950             :     /*
     951             :      * Done! Let others know that we're finished.
     952             :      */
     953    30754376 :     WALInsertLockRelease();
     954             : 
     955    30754376 :     END_CRIT_SECTION();
     956             : 
     957    30754376 :     MarkCurrentTransactionIdLoggedIfAny();
     958             : 
     959             :     /*
     960             :      * Mark top transaction id is logged (if needed) so that we should not try
     961             :      * to log it again with the next WAL record in the current subtransaction.
     962             :      */
     963    30754376 :     if (topxid_included)
     964         438 :         MarkSubxactTopXidLogged();
     965             : 
     966             :     /*
     967             :      * Update shared LogwrtRqst.Write, if we crossed page boundary.
     968             :      */
     969    30754376 :     if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ)
     970             :     {
     971     3390266 :         SpinLockAcquire(&XLogCtl->info_lck);
     972             :         /* advance global request to include new block(s) */
     973     3390266 :         if (XLogCtl->LogwrtRqst.Write < EndPos)
     974     3220534 :             XLogCtl->LogwrtRqst.Write = EndPos;
     975     3390266 :         SpinLockRelease(&XLogCtl->info_lck);
     976     3390266 :         RefreshXLogWriteResult(LogwrtResult);
     977             :     }
     978             : 
     979             :     /*
     980             :      * If this was an XLOG_SWITCH record, flush the record and the empty
     981             :      * padding space that fills the rest of the segment, and perform
     982             :      * end-of-segment actions (eg, notifying archiver).
     983             :      */
     984    30754376 :     if (class == WALINSERT_SPECIAL_SWITCH)
     985             :     {
     986             :         TRACE_POSTGRESQL_WAL_SWITCH();
     987        1576 :         XLogFlush(EndPos);
     988             : 
     989             :         /*
     990             :          * Even though we reserved the rest of the segment for us, which is
     991             :          * reflected in EndPos, we return a pointer to just the end of the
     992             :          * xlog-switch record.
     993             :          */
     994        1576 :         if (inserted)
     995             :         {
     996        1464 :             EndPos = StartPos + SizeOfXLogRecord;
     997        1464 :             if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ)
     998             :             {
     999           2 :                 uint64      offset = XLogSegmentOffset(EndPos, wal_segment_size);
    1000             : 
    1001           2 :                 if (offset == EndPos % XLOG_BLCKSZ)
    1002           0 :                     EndPos += SizeOfXLogLongPHD;
    1003             :                 else
    1004           2 :                     EndPos += SizeOfXLogShortPHD;
    1005             :             }
    1006             :         }
    1007             :     }
    1008             : 
    1009             : #ifdef WAL_DEBUG
    1010             :     if (XLOG_DEBUG)
    1011             :     {
    1012             :         static XLogReaderState *debug_reader = NULL;
    1013             :         XLogRecord *record;
    1014             :         DecodedXLogRecord *decoded;
    1015             :         StringInfoData buf;
    1016             :         StringInfoData recordBuf;
    1017             :         char       *errormsg = NULL;
    1018             :         MemoryContext oldCxt;
    1019             : 
    1020             :         oldCxt = MemoryContextSwitchTo(walDebugCxt);
    1021             : 
    1022             :         initStringInfo(&buf);
    1023             :         appendStringInfo(&buf, "INSERT @ %X/%08X: ", LSN_FORMAT_ARGS(EndPos));
    1024             : 
    1025             :         /*
    1026             :          * We have to piece together the WAL record data from the XLogRecData
    1027             :          * entries, so that we can pass it to the rm_desc function as one
    1028             :          * contiguous chunk.
    1029             :          */
    1030             :         initStringInfo(&recordBuf);
    1031             :         for (; rdata != NULL; rdata = rdata->next)
    1032             :             appendBinaryStringInfo(&recordBuf, rdata->data, rdata->len);
    1033             : 
    1034             :         /* We also need temporary space to decode the record. */
    1035             :         record = (XLogRecord *) recordBuf.data;
    1036             :         decoded = (DecodedXLogRecord *)
    1037             :             palloc(DecodeXLogRecordRequiredSpace(record->xl_tot_len));
    1038             : 
    1039             :         if (!debug_reader)
    1040             :             debug_reader = XLogReaderAllocate(wal_segment_size, NULL,
    1041             :                                               XL_ROUTINE(.page_read = NULL,
    1042             :                                                          .segment_open = NULL,
    1043             :                                                          .segment_close = NULL),
    1044             :                                               NULL);
    1045             :         if (!debug_reader)
    1046             :         {
    1047             :             appendStringInfoString(&buf, "error decoding record: out of memory while allocating a WAL reading processor");
    1048             :         }
    1049             :         else if (!DecodeXLogRecord(debug_reader,
    1050             :                                    decoded,
    1051             :                                    record,
    1052             :                                    EndPos,
    1053             :                                    &errormsg))
    1054             :         {
    1055             :             appendStringInfo(&buf, "error decoding record: %s",
    1056             :                              errormsg ? errormsg : "no error message");
    1057             :         }
    1058             :         else
    1059             :         {
    1060             :             appendStringInfoString(&buf, " - ");
    1061             : 
    1062             :             debug_reader->record = decoded;
    1063             :             xlog_outdesc(&buf, debug_reader);
    1064             :             debug_reader->record = NULL;
    1065             :         }
    1066             :         elog(LOG, "%s", buf.data);
    1067             : 
    1068             :         pfree(decoded);
    1069             :         pfree(buf.data);
    1070             :         pfree(recordBuf.data);
    1071             :         MemoryContextSwitchTo(oldCxt);
    1072             :     }
    1073             : #endif
    1074             : 
    1075             :     /*
    1076             :      * Update our global variables
    1077             :      */
    1078    30754376 :     ProcLastRecPtr = StartPos;
    1079    30754376 :     XactLastRecEnd = EndPos;
    1080             : 
    1081             :     /* Report WAL traffic to the instrumentation. */
    1082    30754376 :     if (inserted)
    1083             :     {
    1084    30754264 :         pgWalUsage.wal_bytes += rechdr->xl_tot_len;
    1085    30754264 :         pgWalUsage.wal_records++;
    1086    30754264 :         pgWalUsage.wal_fpi += num_fpi;
    1087    30754264 :         pgWalUsage.wal_fpi_bytes += fpi_bytes;
    1088             : 
    1089             :         /* Required for the flush of pending stats WAL data */
    1090    30754264 :         pgstat_report_fixed = true;
    1091             :     }
    1092             : 
    1093    30754376 :     return EndPos;
    1094             : }
    1095             : 
    1096             : /*
    1097             :  * Reserves the right amount of space for a record of given size from the WAL.
    1098             :  * *StartPos is set to the beginning of the reserved section, *EndPos to
    1099             :  * its end+1. *PrevPtr is set to the beginning of the previous record; it is
    1100             :  * used to set the xl_prev of this record.
    1101             :  *
    1102             :  * This is the performance critical part of XLogInsert that must be serialized
    1103             :  * across backends. The rest can happen mostly in parallel. Try to keep this
    1104             :  * section as short as possible, insertpos_lck can be heavily contended on a
    1105             :  * busy system.
    1106             :  *
    1107             :  * NB: The space calculation here must match the code in CopyXLogRecordToWAL,
    1108             :  * where we actually copy the record to the reserved space.
    1109             :  *
    1110             :  * NB: Testing shows that XLogInsertRecord runs faster if this code is inlined;
    1111             :  * however, because there are two call sites, the compiler is reluctant to
    1112             :  * inline. We use pg_attribute_always_inline here to try to convince it.
    1113             :  */
    1114             : static pg_attribute_always_inline void
    1115    30752800 : ReserveXLogInsertLocation(int size, XLogRecPtr *StartPos, XLogRecPtr *EndPos,
    1116             :                           XLogRecPtr *PrevPtr)
    1117             : {
    1118    30752800 :     XLogCtlInsert *Insert = &XLogCtl->Insert;
    1119             :     uint64      startbytepos;
    1120             :     uint64      endbytepos;
    1121             :     uint64      prevbytepos;
    1122             : 
    1123    30752800 :     size = MAXALIGN(size);
    1124             : 
    1125             :     /* All (non xlog-switch) records should contain data. */
    1126             :     Assert(size > SizeOfXLogRecord);
    1127             : 
    1128             :     /*
    1129             :      * The duration the spinlock needs to be held is minimized by minimizing
    1130             :      * the calculations that have to be done while holding the lock. The
    1131             :      * current tip of reserved WAL is kept in CurrBytePos, as a byte position
    1132             :      * that only counts "usable" bytes in WAL, that is, it excludes all WAL
    1133             :      * page headers. The mapping between "usable" byte positions and physical
    1134             :      * positions (XLogRecPtrs) can be done outside the locked region, and
    1135             :      * because the usable byte position doesn't include any headers, reserving
    1136             :      * X bytes from WAL is almost as simple as "CurrBytePos += X".
    1137             :      */
    1138    30752800 :     SpinLockAcquire(&Insert->insertpos_lck);
    1139             : 
    1140    30752800 :     startbytepos = Insert->CurrBytePos;
    1141    30752800 :     endbytepos = startbytepos + size;
    1142    30752800 :     prevbytepos = Insert->PrevBytePos;
    1143    30752800 :     Insert->CurrBytePos = endbytepos;
    1144    30752800 :     Insert->PrevBytePos = startbytepos;
    1145             : 
    1146    30752800 :     SpinLockRelease(&Insert->insertpos_lck);
    1147             : 
    1148    30752800 :     *StartPos = XLogBytePosToRecPtr(startbytepos);
    1149    30752800 :     *EndPos = XLogBytePosToEndRecPtr(endbytepos);
    1150    30752800 :     *PrevPtr = XLogBytePosToRecPtr(prevbytepos);
    1151             : 
    1152             :     /*
    1153             :      * Check that the conversions between "usable byte positions" and
    1154             :      * XLogRecPtrs work consistently in both directions.
    1155             :      */
    1156             :     Assert(XLogRecPtrToBytePos(*StartPos) == startbytepos);
    1157             :     Assert(XLogRecPtrToBytePos(*EndPos) == endbytepos);
    1158             :     Assert(XLogRecPtrToBytePos(*PrevPtr) == prevbytepos);
    1159    30752800 : }
    1160             : 
    1161             : /*
    1162             :  * Like ReserveXLogInsertLocation(), but for an xlog-switch record.
    1163             :  *
    1164             :  * A log-switch record is handled slightly differently. The rest of the
    1165             :  * segment will be reserved for this insertion, as indicated by the returned
    1166             :  * *EndPos value. However, if we are already at the beginning of the current
    1167             :  * segment, *StartPos and *EndPos are set to the current location without
    1168             :  * reserving any space, and the function returns false.
    1169             : */
    1170             : static bool
    1171        1576 : ReserveXLogSwitch(XLogRecPtr *StartPos, XLogRecPtr *EndPos, XLogRecPtr *PrevPtr)
    1172             : {
    1173        1576 :     XLogCtlInsert *Insert = &XLogCtl->Insert;
    1174             :     uint64      startbytepos;
    1175             :     uint64      endbytepos;
    1176             :     uint64      prevbytepos;
    1177        1576 :     uint32      size = MAXALIGN(SizeOfXLogRecord);
    1178             :     XLogRecPtr  ptr;
    1179             :     uint32      segleft;
    1180             : 
    1181             :     /*
    1182             :      * These calculations are a bit heavy-weight to be done while holding a
    1183             :      * spinlock, but since we're holding all the WAL insertion locks, there
    1184             :      * are no other inserters competing for it. GetXLogInsertRecPtr() does
    1185             :      * compete for it, but that's not called very frequently.
    1186             :      */
    1187        1576 :     SpinLockAcquire(&Insert->insertpos_lck);
    1188             : 
    1189        1576 :     startbytepos = Insert->CurrBytePos;
    1190             : 
    1191        1576 :     ptr = XLogBytePosToEndRecPtr(startbytepos);
    1192        1576 :     if (XLogSegmentOffset(ptr, wal_segment_size) == 0)
    1193             :     {
    1194         112 :         SpinLockRelease(&Insert->insertpos_lck);
    1195         112 :         *EndPos = *StartPos = ptr;
    1196         112 :         return false;
    1197             :     }
    1198             : 
    1199        1464 :     endbytepos = startbytepos + size;
    1200        1464 :     prevbytepos = Insert->PrevBytePos;
    1201             : 
    1202        1464 :     *StartPos = XLogBytePosToRecPtr(startbytepos);
    1203        1464 :     *EndPos = XLogBytePosToEndRecPtr(endbytepos);
    1204             : 
    1205        1464 :     segleft = wal_segment_size - XLogSegmentOffset(*EndPos, wal_segment_size);
    1206        1464 :     if (segleft != wal_segment_size)
    1207             :     {
    1208             :         /* consume the rest of the segment */
    1209        1464 :         *EndPos += segleft;
    1210        1464 :         endbytepos = XLogRecPtrToBytePos(*EndPos);
    1211             :     }
    1212        1464 :     Insert->CurrBytePos = endbytepos;
    1213        1464 :     Insert->PrevBytePos = startbytepos;
    1214             : 
    1215        1464 :     SpinLockRelease(&Insert->insertpos_lck);
    1216             : 
    1217        1464 :     *PrevPtr = XLogBytePosToRecPtr(prevbytepos);
    1218             : 
    1219             :     Assert(XLogSegmentOffset(*EndPos, wal_segment_size) == 0);
    1220             :     Assert(XLogRecPtrToBytePos(*EndPos) == endbytepos);
    1221             :     Assert(XLogRecPtrToBytePos(*StartPos) == startbytepos);
    1222             :     Assert(XLogRecPtrToBytePos(*PrevPtr) == prevbytepos);
    1223             : 
    1224        1464 :     return true;
    1225             : }
    1226             : 
    1227             : /*
    1228             :  * Subroutine of XLogInsertRecord.  Copies a WAL record to an already-reserved
    1229             :  * area in the WAL.
    1230             :  */
    1231             : static void
    1232    30754264 : CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
    1233             :                     XLogRecPtr StartPos, XLogRecPtr EndPos, TimeLineID tli)
    1234             : {
    1235             :     char       *currpos;
    1236             :     int         freespace;
    1237             :     int         written;
    1238             :     XLogRecPtr  CurrPos;
    1239             :     XLogPageHeader pagehdr;
    1240             : 
    1241             :     /*
    1242             :      * Get a pointer to the right place in the right WAL buffer to start
    1243             :      * inserting to.
    1244             :      */
    1245    30754264 :     CurrPos = StartPos;
    1246    30754264 :     currpos = GetXLogBuffer(CurrPos, tli);
    1247    30754264 :     freespace = INSERT_FREESPACE(CurrPos);
    1248             : 
    1249             :     /*
    1250             :      * there should be enough space for at least the first field (xl_tot_len)
    1251             :      * on this page.
    1252             :      */
    1253             :     Assert(freespace >= sizeof(uint32));
    1254             : 
    1255             :     /* Copy record data */
    1256    30754264 :     written = 0;
    1257   145109586 :     while (rdata != NULL)
    1258             :     {
    1259   114355322 :         const char *rdata_data = rdata->data;
    1260   114355322 :         int         rdata_len = rdata->len;
    1261             : 
    1262   117964058 :         while (rdata_len > freespace)
    1263             :         {
    1264             :             /*
    1265             :              * Write what fits on this page, and continue on the next page.
    1266             :              */
    1267             :             Assert(CurrPos % XLOG_BLCKSZ >= SizeOfXLogShortPHD || freespace == 0);
    1268     3608736 :             memcpy(currpos, rdata_data, freespace);
    1269     3608736 :             rdata_data += freespace;
    1270     3608736 :             rdata_len -= freespace;
    1271     3608736 :             written += freespace;
    1272     3608736 :             CurrPos += freespace;
    1273             : 
    1274             :             /*
    1275             :              * Get pointer to beginning of next page, and set the xlp_rem_len
    1276             :              * in the page header. Set XLP_FIRST_IS_CONTRECORD.
    1277             :              *
    1278             :              * It's safe to set the contrecord flag and xlp_rem_len without a
    1279             :              * lock on the page. All the other flags were already set when the
    1280             :              * page was initialized, in AdvanceXLInsertBuffer, and we're the
    1281             :              * only backend that needs to set the contrecord flag.
    1282             :              */
    1283     3608736 :             currpos = GetXLogBuffer(CurrPos, tli);
    1284     3608736 :             pagehdr = (XLogPageHeader) currpos;
    1285     3608736 :             pagehdr->xlp_rem_len = write_len - written;
    1286     3608736 :             pagehdr->xlp_info |= XLP_FIRST_IS_CONTRECORD;
    1287             : 
    1288             :             /* skip over the page header */
    1289     3608736 :             if (XLogSegmentOffset(CurrPos, wal_segment_size) == 0)
    1290             :             {
    1291        2330 :                 CurrPos += SizeOfXLogLongPHD;
    1292        2330 :                 currpos += SizeOfXLogLongPHD;
    1293             :             }
    1294             :             else
    1295             :             {
    1296     3606406 :                 CurrPos += SizeOfXLogShortPHD;
    1297     3606406 :                 currpos += SizeOfXLogShortPHD;
    1298             :             }
    1299     3608736 :             freespace = INSERT_FREESPACE(CurrPos);
    1300             :         }
    1301             : 
    1302             :         Assert(CurrPos % XLOG_BLCKSZ >= SizeOfXLogShortPHD || rdata_len == 0);
    1303   114355322 :         memcpy(currpos, rdata_data, rdata_len);
    1304   114355322 :         currpos += rdata_len;
    1305   114355322 :         CurrPos += rdata_len;
    1306   114355322 :         freespace -= rdata_len;
    1307   114355322 :         written += rdata_len;
    1308             : 
    1309   114355322 :         rdata = rdata->next;
    1310             :     }
    1311             :     Assert(written == write_len);
    1312             : 
    1313             :     /*
    1314             :      * If this was an xlog-switch, it's not enough to write the switch record,
    1315             :      * we also have to consume all the remaining space in the WAL segment.  We
    1316             :      * have already reserved that space, but we need to actually fill it.
    1317             :      */
    1318    30754264 :     if (isLogSwitch && XLogSegmentOffset(CurrPos, wal_segment_size) != 0)
    1319             :     {
    1320             :         /* An xlog-switch record doesn't contain any data besides the header */
    1321             :         Assert(write_len == SizeOfXLogRecord);
    1322             : 
    1323             :         /* Assert that we did reserve the right amount of space */
    1324             :         Assert(XLogSegmentOffset(EndPos, wal_segment_size) == 0);
    1325             : 
    1326             :         /* Use up all the remaining space on the current page */
    1327        1464 :         CurrPos += freespace;
    1328             : 
    1329             :         /*
    1330             :          * Cause all remaining pages in the segment to be flushed, leaving the
    1331             :          * XLog position where it should be, at the start of the next segment.
    1332             :          * We do this one page at a time, to make sure we don't deadlock
    1333             :          * against ourselves if wal_buffers < wal_segment_size.
    1334             :          */
    1335     1422228 :         while (CurrPos < EndPos)
    1336             :         {
    1337             :             /*
    1338             :              * The minimal action to flush the page would be to call
    1339             :              * WALInsertLockUpdateInsertingAt(CurrPos) followed by
    1340             :              * AdvanceXLInsertBuffer(...).  The page would be left initialized
    1341             :              * mostly to zeros, except for the page header (always the short
    1342             :              * variant, as this is never a segment's first page).
    1343             :              *
    1344             :              * The large vistas of zeros are good for compressibility, but the
    1345             :              * headers interrupting them every XLOG_BLCKSZ (with values that
    1346             :              * differ from page to page) are not.  The effect varies with
    1347             :              * compression tool, but bzip2 for instance compresses about an
    1348             :              * order of magnitude worse if those headers are left in place.
    1349             :              *
    1350             :              * Rather than complicating AdvanceXLInsertBuffer itself (which is
    1351             :              * called in heavily-loaded circumstances as well as this lightly-
    1352             :              * loaded one) with variant behavior, we just use GetXLogBuffer
    1353             :              * (which itself calls the two methods we need) to get the pointer
    1354             :              * and zero most of the page.  Then we just zero the page header.
    1355             :              */
    1356     1420764 :             currpos = GetXLogBuffer(CurrPos, tli);
    1357     5683056 :             MemSet(currpos, 0, SizeOfXLogShortPHD);
    1358             : 
    1359     1420764 :             CurrPos += XLOG_BLCKSZ;
    1360             :         }
    1361             :     }
    1362             :     else
    1363             :     {
    1364             :         /* Align the end position, so that the next record starts aligned */
    1365    30752800 :         CurrPos = MAXALIGN64(CurrPos);
    1366             :     }
    1367             : 
    1368    30754264 :     if (CurrPos != EndPos)
    1369           0 :         ereport(PANIC,
    1370             :                 errcode(ERRCODE_DATA_CORRUPTED),
    1371             :                 errmsg_internal("space reserved for WAL record does not match what was written"));
    1372    30754264 : }
    1373             : 
    1374             : /*
    1375             :  * Acquire a WAL insertion lock, for inserting to WAL.
    1376             :  */
    1377             : static void
    1378    30766944 : WALInsertLockAcquire(void)
    1379             : {
    1380             :     bool        immed;
    1381             : 
    1382             :     /*
    1383             :      * It doesn't matter which of the WAL insertion locks we acquire, so try
    1384             :      * the one we used last time.  If the system isn't particularly busy, it's
    1385             :      * a good bet that it's still available, and it's good to have some
    1386             :      * affinity to a particular lock so that you don't unnecessarily bounce
    1387             :      * cache lines between processes when there's no contention.
    1388             :      *
    1389             :      * If this is the first time through in this backend, pick a lock
    1390             :      * (semi-)randomly.  This allows the locks to be used evenly if you have a
    1391             :      * lot of very short connections.
    1392             :      */
    1393             :     static int  lockToTry = -1;
    1394             : 
    1395    30766944 :     if (lockToTry == -1)
    1396       16798 :         lockToTry = MyProcNumber % NUM_XLOGINSERT_LOCKS;
    1397    30766944 :     MyLockNo = lockToTry;
    1398             : 
    1399             :     /*
    1400             :      * The insertingAt value is initially set to 0, as we don't know our
    1401             :      * insert location yet.
    1402             :      */
    1403    30766944 :     immed = LWLockAcquire(&WALInsertLocks[MyLockNo].l.lock, LW_EXCLUSIVE);
    1404    30766944 :     if (!immed)
    1405             :     {
    1406             :         /*
    1407             :          * If we couldn't get the lock immediately, try another lock next
    1408             :          * time.  On a system with more insertion locks than concurrent
    1409             :          * inserters, this causes all the inserters to eventually migrate to a
    1410             :          * lock that no-one else is using.  On a system with more inserters
    1411             :          * than locks, it still helps to distribute the inserters evenly
    1412             :          * across the locks.
    1413             :          */
    1414       54172 :         lockToTry = (lockToTry + 1) % NUM_XLOGINSERT_LOCKS;
    1415             :     }
    1416    30766944 : }
    1417             : 
    1418             : /*
    1419             :  * Acquire all WAL insertion locks, to prevent other backends from inserting
    1420             :  * to WAL.
    1421             :  */
    1422             : static void
    1423        8862 : WALInsertLockAcquireExclusive(void)
    1424             : {
    1425             :     int         i;
    1426             : 
    1427             :     /*
    1428             :      * When holding all the locks, all but the last lock's insertingAt
    1429             :      * indicator is set to 0xFFFFFFFFFFFFFFFF, which is higher than any real
    1430             :      * XLogRecPtr value, to make sure that no-one blocks waiting on those.
    1431             :      */
    1432       70896 :     for (i = 0; i < NUM_XLOGINSERT_LOCKS - 1; i++)
    1433             :     {
    1434       62034 :         LWLockAcquire(&WALInsertLocks[i].l.lock, LW_EXCLUSIVE);
    1435       62034 :         LWLockUpdateVar(&WALInsertLocks[i].l.lock,
    1436       62034 :                         &WALInsertLocks[i].l.insertingAt,
    1437             :                         PG_UINT64_MAX);
    1438             :     }
    1439             :     /* Variable value reset to 0 at release */
    1440        8862 :     LWLockAcquire(&WALInsertLocks[i].l.lock, LW_EXCLUSIVE);
    1441             : 
    1442        8862 :     holdingAllLocks = true;
    1443        8862 : }
    1444             : 
    1445             : /*
    1446             :  * Release our insertion lock (or locks, if we're holding them all).
    1447             :  *
    1448             :  * NB: Reset all variables to 0, so they cause LWLockWaitForVar to block the
    1449             :  * next time the lock is acquired.
    1450             :  */
    1451             : static void
    1452    30775806 : WALInsertLockRelease(void)
    1453             : {
    1454    30775806 :     if (holdingAllLocks)
    1455             :     {
    1456             :         int         i;
    1457             : 
    1458       79758 :         for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++)
    1459       70896 :             LWLockReleaseClearVar(&WALInsertLocks[i].l.lock,
    1460       70896 :                                   &WALInsertLocks[i].l.insertingAt,
    1461             :                                   0);
    1462             : 
    1463        8862 :         holdingAllLocks = false;
    1464             :     }
    1465             :     else
    1466             :     {
    1467    30766944 :         LWLockReleaseClearVar(&WALInsertLocks[MyLockNo].l.lock,
    1468    30766944 :                               &WALInsertLocks[MyLockNo].l.insertingAt,
    1469             :                               0);
    1470             :     }
    1471    30775806 : }
    1472             : 
    1473             : /*
    1474             :  * Update our insertingAt value, to let others know that we've finished
    1475             :  * inserting up to that point.
    1476             :  */
    1477             : static void
    1478     5330104 : WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt)
    1479             : {
    1480     5330104 :     if (holdingAllLocks)
    1481             :     {
    1482             :         /*
    1483             :          * We use the last lock to mark our actual position, see comments in
    1484             :          * WALInsertLockAcquireExclusive.
    1485             :          */
    1486     1415354 :         LWLockUpdateVar(&WALInsertLocks[NUM_XLOGINSERT_LOCKS - 1].l.lock,
    1487     1415354 :                         &WALInsertLocks[NUM_XLOGINSERT_LOCKS - 1].l.insertingAt,
    1488             :                         insertingAt);
    1489             :     }
    1490             :     else
    1491     3914750 :         LWLockUpdateVar(&WALInsertLocks[MyLockNo].l.lock,
    1492     3914750 :                         &WALInsertLocks[MyLockNo].l.insertingAt,
    1493             :                         insertingAt);
    1494     5330104 : }
    1495             : 
    1496             : /*
    1497             :  * Wait for any WAL insertions < upto to finish.
    1498             :  *
    1499             :  * Returns the location of the oldest insertion that is still in-progress.
    1500             :  * Any WAL prior to that point has been fully copied into WAL buffers, and
    1501             :  * can be flushed out to disk. Because this waits for any insertions older
    1502             :  * than 'upto' to finish, the return value is always >= 'upto'.
    1503             :  *
    1504             :  * Note: When you are about to write out WAL, you must call this function
    1505             :  * *before* acquiring WALWriteLock, to avoid deadlocks. This function might
    1506             :  * need to wait for an insertion to finish (or at least advance to next
    1507             :  * uninitialized page), and the inserter might need to evict an old WAL buffer
    1508             :  * to make room for a new one, which in turn requires WALWriteLock.
    1509             :  */
    1510             : static XLogRecPtr
    1511     4880086 : WaitXLogInsertionsToFinish(XLogRecPtr upto)
    1512             : {
    1513             :     uint64      bytepos;
    1514             :     XLogRecPtr  inserted;
    1515             :     XLogRecPtr  reservedUpto;
    1516             :     XLogRecPtr  finishedUpto;
    1517     4880086 :     XLogCtlInsert *Insert = &XLogCtl->Insert;
    1518             :     int         i;
    1519             : 
    1520     4880086 :     if (MyProc == NULL)
    1521           0 :         elog(PANIC, "cannot wait without a PGPROC structure");
    1522             : 
    1523             :     /*
    1524             :      * Check if there's any work to do.  Use a barrier to ensure we get the
    1525             :      * freshest value.
    1526             :      */
    1527     4880086 :     inserted = pg_atomic_read_membarrier_u64(&XLogCtl->logInsertResult);
    1528     4880086 :     if (upto <= inserted)
    1529     3995254 :         return inserted;
    1530             : 
    1531             :     /* Read the current insert position */
    1532      884832 :     SpinLockAcquire(&Insert->insertpos_lck);
    1533      884832 :     bytepos = Insert->CurrBytePos;
    1534      884832 :     SpinLockRelease(&Insert->insertpos_lck);
    1535      884832 :     reservedUpto = XLogBytePosToEndRecPtr(bytepos);
    1536             : 
    1537             :     /*
    1538             :      * No-one should request to flush a piece of WAL that hasn't even been
    1539             :      * reserved yet. However, it can happen if there is a block with a bogus
    1540             :      * LSN on disk, for example. XLogFlush checks for that situation and
    1541             :      * complains, but only after the flush. Here we just assume that to mean
    1542             :      * that all WAL that has been reserved needs to be finished. In this
    1543             :      * corner-case, the return value can be smaller than 'upto' argument.
    1544             :      */
    1545      884832 :     if (upto > reservedUpto)
    1546             :     {
    1547           0 :         ereport(LOG,
    1548             :                 errmsg("request to flush past end of generated WAL; request %X/%08X, current position %X/%08X",
    1549             :                        LSN_FORMAT_ARGS(upto), LSN_FORMAT_ARGS(reservedUpto)));
    1550           0 :         upto = reservedUpto;
    1551             :     }
    1552             : 
    1553             :     /*
    1554             :      * Loop through all the locks, sleeping on any in-progress insert older
    1555             :      * than 'upto'.
    1556             :      *
    1557             :      * finishedUpto is our return value, indicating the point upto which all
    1558             :      * the WAL insertions have been finished. Initialize it to the head of
    1559             :      * reserved WAL, and as we iterate through the insertion locks, back it
    1560             :      * out for any insertion that's still in progress.
    1561             :      */
    1562      884832 :     finishedUpto = reservedUpto;
    1563     7963488 :     for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++)
    1564             :     {
    1565     7078656 :         XLogRecPtr  insertingat = InvalidXLogRecPtr;
    1566             : 
    1567             :         do
    1568             :         {
    1569             :             /*
    1570             :              * See if this insertion is in progress.  LWLockWaitForVar will
    1571             :              * wait for the lock to be released, or for the 'value' to be set
    1572             :              * by a LWLockUpdateVar call.  When a lock is initially acquired,
    1573             :              * its value is 0 (InvalidXLogRecPtr), which means that we don't
    1574             :              * know where it's inserting yet.  We will have to wait for it. If
    1575             :              * it's a small insertion, the record will most likely fit on the
    1576             :              * same page and the inserter will release the lock without ever
    1577             :              * calling LWLockUpdateVar.  But if it has to sleep, it will
    1578             :              * advertise the insertion point with LWLockUpdateVar before
    1579             :              * sleeping.
    1580             :              *
    1581             :              * In this loop we are only waiting for insertions that started
    1582             :              * before WaitXLogInsertionsToFinish was called.  The lack of
    1583             :              * memory barriers in the loop means that we might see locks as
    1584             :              * "unused" that have since become used.  This is fine because
    1585             :              * they only can be used for later insertions that we would not
    1586             :              * want to wait on anyway.  Not taking a lock to acquire the
    1587             :              * current insertingAt value means that we might see older
    1588             :              * insertingAt values.  This is also fine, because if we read a
    1589             :              * value too old, we will add ourselves to the wait queue, which
    1590             :              * contains atomic operations.
    1591             :              */
    1592     7228686 :             if (LWLockWaitForVar(&WALInsertLocks[i].l.lock,
    1593     7228686 :                                  &WALInsertLocks[i].l.insertingAt,
    1594             :                                  insertingat, &insertingat))
    1595             :             {
    1596             :                 /* the lock was free, so no insertion in progress */
    1597     5160134 :                 insertingat = InvalidXLogRecPtr;
    1598     5160134 :                 break;
    1599             :             }
    1600             : 
    1601             :             /*
    1602             :              * This insertion is still in progress. Have to wait, unless the
    1603             :              * inserter has proceeded past 'upto'.
    1604             :              */
    1605     2068552 :         } while (insertingat < upto);
    1606             : 
    1607     7078656 :         if (XLogRecPtrIsValid(insertingat) && insertingat < finishedUpto)
    1608      749922 :             finishedUpto = insertingat;
    1609             :     }
    1610             : 
    1611             :     /*
    1612             :      * Advance the limit we know to have been inserted and return the freshest
    1613             :      * value we know of, which might be beyond what we requested if somebody
    1614             :      * is concurrently doing this with an 'upto' pointer ahead of us.
    1615             :      */
    1616      884832 :     finishedUpto = pg_atomic_monotonic_advance_u64(&XLogCtl->logInsertResult,
    1617             :                                                    finishedUpto);
    1618             : 
    1619      884832 :     return finishedUpto;
    1620             : }
    1621             : 
    1622             : /*
    1623             :  * Get a pointer to the right location in the WAL buffer containing the
    1624             :  * given XLogRecPtr.
    1625             :  *
    1626             :  * If the page is not initialized yet, it is initialized. That might require
    1627             :  * evicting an old dirty buffer from the buffer cache, which means I/O.
    1628             :  *
    1629             :  * The caller must ensure that the page containing the requested location
    1630             :  * isn't evicted yet, and won't be evicted. The way to ensure that is to
    1631             :  * hold onto a WAL insertion lock with the insertingAt position set to
    1632             :  * something <= ptr. GetXLogBuffer() will update insertingAt if it needs
    1633             :  * to evict an old page from the buffer. (This means that once you call
    1634             :  * GetXLogBuffer() with a given 'ptr', you must not access anything before
    1635             :  * that point anymore, and must not call GetXLogBuffer() with an older 'ptr'
    1636             :  * later, because older buffers might be recycled already)
    1637             :  */
    1638             : static char *
    1639    35783786 : GetXLogBuffer(XLogRecPtr ptr, TimeLineID tli)
    1640             : {
    1641             :     int         idx;
    1642             :     XLogRecPtr  endptr;
    1643             :     static uint64 cachedPage = 0;
    1644             :     static char *cachedPos = NULL;
    1645             :     XLogRecPtr  expectedEndPtr;
    1646             : 
    1647             :     /*
    1648             :      * Fast path for the common case that we need to access again the same
    1649             :      * page as last time.
    1650             :      */
    1651    35783786 :     if (ptr / XLOG_BLCKSZ == cachedPage)
    1652             :     {
    1653             :         Assert(((XLogPageHeader) cachedPos)->xlp_magic == XLOG_PAGE_MAGIC);
    1654             :         Assert(((XLogPageHeader) cachedPos)->xlp_pageaddr == ptr - (ptr % XLOG_BLCKSZ));
    1655    29404126 :         return cachedPos + ptr % XLOG_BLCKSZ;
    1656             :     }
    1657             : 
    1658             :     /*
    1659             :      * The XLog buffer cache is organized so that a page is always loaded to a
    1660             :      * particular buffer.  That way we can easily calculate the buffer a given
    1661             :      * page must be loaded into, from the XLogRecPtr alone.
    1662             :      */
    1663     6379660 :     idx = XLogRecPtrToBufIdx(ptr);
    1664             : 
    1665             :     /*
    1666             :      * See what page is loaded in the buffer at the moment. It could be the
    1667             :      * page we're looking for, or something older. It can't be anything newer
    1668             :      * - that would imply the page we're looking for has already been written
    1669             :      * out to disk and evicted, and the caller is responsible for making sure
    1670             :      * that doesn't happen.
    1671             :      *
    1672             :      * We don't hold a lock while we read the value. If someone is just about
    1673             :      * to initialize or has just initialized the page, it's possible that we
    1674             :      * get InvalidXLogRecPtr. That's ok, we'll grab the mapping lock (in
    1675             :      * AdvanceXLInsertBuffer) and retry if we see anything other than the page
    1676             :      * we're looking for.
    1677             :      */
    1678     6379660 :     expectedEndPtr = ptr;
    1679     6379660 :     expectedEndPtr += XLOG_BLCKSZ - ptr % XLOG_BLCKSZ;
    1680             : 
    1681     6379660 :     endptr = pg_atomic_read_u64(&XLogCtl->xlblocks[idx]);
    1682     6379660 :     if (expectedEndPtr != endptr)
    1683             :     {
    1684             :         XLogRecPtr  initializedUpto;
    1685             : 
    1686             :         /*
    1687             :          * Before calling AdvanceXLInsertBuffer(), which can block, let others
    1688             :          * know how far we're finished with inserting the record.
    1689             :          *
    1690             :          * NB: If 'ptr' points to just after the page header, advertise a
    1691             :          * position at the beginning of the page rather than 'ptr' itself. If
    1692             :          * there are no other insertions running, someone might try to flush
    1693             :          * up to our advertised location. If we advertised a position after
    1694             :          * the page header, someone might try to flush the page header, even
    1695             :          * though page might actually not be initialized yet. As the first
    1696             :          * inserter on the page, we are effectively responsible for making
    1697             :          * sure that it's initialized, before we let insertingAt to move past
    1698             :          * the page header.
    1699             :          */
    1700     5330104 :         if (ptr % XLOG_BLCKSZ == SizeOfXLogShortPHD &&
    1701       12698 :             XLogSegmentOffset(ptr, wal_segment_size) > XLOG_BLCKSZ)
    1702       12698 :             initializedUpto = ptr - SizeOfXLogShortPHD;
    1703     5317406 :         else if (ptr % XLOG_BLCKSZ == SizeOfXLogLongPHD &&
    1704        2544 :                  XLogSegmentOffset(ptr, wal_segment_size) < XLOG_BLCKSZ)
    1705        1244 :             initializedUpto = ptr - SizeOfXLogLongPHD;
    1706             :         else
    1707     5316162 :             initializedUpto = ptr;
    1708             : 
    1709     5330104 :         WALInsertLockUpdateInsertingAt(initializedUpto);
    1710             : 
    1711     5330104 :         AdvanceXLInsertBuffer(ptr, tli, false);
    1712     5330104 :         endptr = pg_atomic_read_u64(&XLogCtl->xlblocks[idx]);
    1713             : 
    1714     5330104 :         if (expectedEndPtr != endptr)
    1715           0 :             elog(PANIC, "could not find WAL buffer for %X/%08X",
    1716             :                  LSN_FORMAT_ARGS(ptr));
    1717             :     }
    1718             :     else
    1719             :     {
    1720             :         /*
    1721             :          * Make sure the initialization of the page is visible to us, and
    1722             :          * won't arrive later to overwrite the WAL data we write on the page.
    1723             :          */
    1724     1049556 :         pg_memory_barrier();
    1725             :     }
    1726             : 
    1727             :     /*
    1728             :      * Found the buffer holding this page. Return a pointer to the right
    1729             :      * offset within the page.
    1730             :      */
    1731     6379660 :     cachedPage = ptr / XLOG_BLCKSZ;
    1732     6379660 :     cachedPos = XLogCtl->pages + idx * (Size) XLOG_BLCKSZ;
    1733             : 
    1734             :     Assert(((XLogPageHeader) cachedPos)->xlp_magic == XLOG_PAGE_MAGIC);
    1735             :     Assert(((XLogPageHeader) cachedPos)->xlp_pageaddr == ptr - (ptr % XLOG_BLCKSZ));
    1736             : 
    1737     6379660 :     return cachedPos + ptr % XLOG_BLCKSZ;
    1738             : }
    1739             : 
    1740             : /*
    1741             :  * Read WAL data directly from WAL buffers, if available. Returns the number
    1742             :  * of bytes read successfully.
    1743             :  *
    1744             :  * Fewer than 'count' bytes may be read if some of the requested WAL data has
    1745             :  * already been evicted.
    1746             :  *
    1747             :  * No locks are taken.
    1748             :  *
    1749             :  * Caller should ensure that it reads no further than LogwrtResult.Write
    1750             :  * (which should have been updated by the caller when determining how far to
    1751             :  * read). The 'tli' argument is only used as a convenient safety check so that
    1752             :  * callers do not read from WAL buffers on a historical timeline.
    1753             :  */
    1754             : Size
    1755      196616 : WALReadFromBuffers(char *dstbuf, XLogRecPtr startptr, Size count,
    1756             :                    TimeLineID tli)
    1757             : {
    1758      196616 :     char       *pdst = dstbuf;
    1759      196616 :     XLogRecPtr  recptr = startptr;
    1760             :     XLogRecPtr  inserted;
    1761      196616 :     Size        nbytes = count;
    1762             : 
    1763      196616 :     if (RecoveryInProgress() || tli != GetWALInsertionTimeLine())
    1764        1778 :         return 0;
    1765             : 
    1766             :     Assert(XLogRecPtrIsValid(startptr));
    1767             : 
    1768             :     /*
    1769             :      * Caller should ensure that the requested data has been inserted into WAL
    1770             :      * buffers before we try to read it.
    1771             :      */
    1772      194838 :     inserted = pg_atomic_read_u64(&XLogCtl->logInsertResult);
    1773      194838 :     if (startptr + count > inserted)
    1774           0 :         ereport(ERROR,
    1775             :                 errmsg("cannot read past end of generated WAL: requested %X/%08X, current position %X/%08X",
    1776             :                        LSN_FORMAT_ARGS(startptr + count),
    1777             :                        LSN_FORMAT_ARGS(inserted)));
    1778             : 
    1779             :     /*
    1780             :      * Loop through the buffers without a lock. For each buffer, atomically
    1781             :      * read and verify the end pointer, then copy the data out, and finally
    1782             :      * re-read and re-verify the end pointer.
    1783             :      *
    1784             :      * Once a page is evicted, it never returns to the WAL buffers, so if the
    1785             :      * end pointer matches the expected end pointer before and after we copy
    1786             :      * the data, then the right page must have been present during the data
    1787             :      * copy. Read barriers are necessary to ensure that the data copy actually
    1788             :      * happens between the two verification steps.
    1789             :      *
    1790             :      * If either verification fails, we simply terminate the loop and return
    1791             :      * with the data that had been already copied out successfully.
    1792             :      */
    1793      206560 :     while (nbytes > 0)
    1794             :     {
    1795      202874 :         uint32      offset = recptr % XLOG_BLCKSZ;
    1796      202874 :         int         idx = XLogRecPtrToBufIdx(recptr);
    1797             :         XLogRecPtr  expectedEndPtr;
    1798             :         XLogRecPtr  endptr;
    1799             :         const char *page;
    1800             :         const char *psrc;
    1801             :         Size        npagebytes;
    1802             : 
    1803             :         /*
    1804             :          * Calculate the end pointer we expect in the xlblocks array if the
    1805             :          * correct page is present.
    1806             :          */
    1807      202874 :         expectedEndPtr = recptr + (XLOG_BLCKSZ - offset);
    1808             : 
    1809             :         /*
    1810             :          * First verification step: check that the correct page is present in
    1811             :          * the WAL buffers.
    1812             :          */
    1813      202874 :         endptr = pg_atomic_read_u64(&XLogCtl->xlblocks[idx]);
    1814      202874 :         if (expectedEndPtr != endptr)
    1815      191150 :             break;
    1816             : 
    1817             :         /*
    1818             :          * The correct page is present (or was at the time the endptr was
    1819             :          * read; must re-verify later). Calculate pointer to source data and
    1820             :          * determine how much data to read from this page.
    1821             :          */
    1822       11724 :         page = XLogCtl->pages + idx * (Size) XLOG_BLCKSZ;
    1823       11724 :         psrc = page + offset;
    1824       11724 :         npagebytes = Min(nbytes, XLOG_BLCKSZ - offset);
    1825             : 
    1826             :         /*
    1827             :          * Ensure that the data copy and the first verification step are not
    1828             :          * reordered.
    1829             :          */
    1830       11724 :         pg_read_barrier();
    1831             : 
    1832             :         /* data copy */
    1833       11724 :         memcpy(pdst, psrc, npagebytes);
    1834             : 
    1835             :         /*
    1836             :          * Ensure that the data copy and the second verification step are not
    1837             :          * reordered.
    1838             :          */
    1839       11724 :         pg_read_barrier();
    1840             : 
    1841             :         /*
    1842             :          * Second verification step: check that the page we read from wasn't
    1843             :          * evicted while we were copying the data.
    1844             :          */
    1845       11724 :         endptr = pg_atomic_read_u64(&XLogCtl->xlblocks[idx]);
    1846       11724 :         if (expectedEndPtr != endptr)
    1847           2 :             break;
    1848             : 
    1849       11722 :         pdst += npagebytes;
    1850       11722 :         recptr += npagebytes;
    1851       11722 :         nbytes -= npagebytes;
    1852             :     }
    1853             : 
    1854             :     Assert(pdst - dstbuf <= count);
    1855             : 
    1856      194838 :     return pdst - dstbuf;
    1857             : }
    1858             : 
    1859             : /*
    1860             :  * Converts a "usable byte position" to XLogRecPtr. A usable byte position
    1861             :  * is the position starting from the beginning of WAL, excluding all WAL
    1862             :  * page headers.
    1863             :  */
    1864             : static XLogRecPtr
    1865    61513868 : XLogBytePosToRecPtr(uint64 bytepos)
    1866             : {
    1867             :     uint64      fullsegs;
    1868             :     uint64      fullpages;
    1869             :     uint64      bytesleft;
    1870             :     uint32      seg_offset;
    1871             :     XLogRecPtr  result;
    1872             : 
    1873    61513868 :     fullsegs = bytepos / UsableBytesInSegment;
    1874    61513868 :     bytesleft = bytepos % UsableBytesInSegment;
    1875             : 
    1876    61513868 :     if (bytesleft < XLOG_BLCKSZ - SizeOfXLogLongPHD)
    1877             :     {
    1878             :         /* fits on first page of segment */
    1879      116838 :         seg_offset = bytesleft + SizeOfXLogLongPHD;
    1880             :     }
    1881             :     else
    1882             :     {
    1883             :         /* account for the first page on segment with long header */
    1884    61397030 :         seg_offset = XLOG_BLCKSZ;
    1885    61397030 :         bytesleft -= XLOG_BLCKSZ - SizeOfXLogLongPHD;
    1886             : 
    1887    61397030 :         fullpages = bytesleft / UsableBytesInPage;
    1888    61397030 :         bytesleft = bytesleft % UsableBytesInPage;
    1889             : 
    1890    61397030 :         seg_offset += fullpages * XLOG_BLCKSZ + bytesleft + SizeOfXLogShortPHD;
    1891             :     }
    1892             : 
    1893    61513868 :     XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, wal_segment_size, result);
    1894             : 
    1895    61513868 :     return result;
    1896             : }
    1897             : 
    1898             : /*
    1899             :  * Like XLogBytePosToRecPtr, but if the position is at a page boundary,
    1900             :  * returns a pointer to the beginning of the page (ie. before page header),
    1901             :  * not to where the first xlog record on that page would go to. This is used
    1902             :  * when converting a pointer to the end of a record.
    1903             :  */
    1904             : static XLogRecPtr
    1905    31640672 : XLogBytePosToEndRecPtr(uint64 bytepos)
    1906             : {
    1907             :     uint64      fullsegs;
    1908             :     uint64      fullpages;
    1909             :     uint64      bytesleft;
    1910             :     uint32      seg_offset;
    1911             :     XLogRecPtr  result;
    1912             : 
    1913    31640672 :     fullsegs = bytepos / UsableBytesInSegment;
    1914    31640672 :     bytesleft = bytepos % UsableBytesInSegment;
    1915             : 
    1916    31640672 :     if (bytesleft < XLOG_BLCKSZ - SizeOfXLogLongPHD)
    1917             :     {
    1918             :         /* fits on first page of segment */
    1919      174956 :         if (bytesleft == 0)
    1920      113814 :             seg_offset = 0;
    1921             :         else
    1922       61142 :             seg_offset = bytesleft + SizeOfXLogLongPHD;
    1923             :     }
    1924             :     else
    1925             :     {
    1926             :         /* account for the first page on segment with long header */
    1927    31465716 :         seg_offset = XLOG_BLCKSZ;
    1928    31465716 :         bytesleft -= XLOG_BLCKSZ - SizeOfXLogLongPHD;
    1929             : 
    1930    31465716 :         fullpages = bytesleft / UsableBytesInPage;
    1931    31465716 :         bytesleft = bytesleft % UsableBytesInPage;
    1932             : 
    1933    31465716 :         if (bytesleft == 0)
    1934       29830 :             seg_offset += fullpages * XLOG_BLCKSZ + bytesleft;
    1935             :         else
    1936    31435886 :             seg_offset += fullpages * XLOG_BLCKSZ + bytesleft + SizeOfXLogShortPHD;
    1937             :     }
    1938             : 
    1939    31640672 :     XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, wal_segment_size, result);
    1940             : 
    1941    31640672 :     return result;
    1942             : }
    1943             : 
    1944             : /*
    1945             :  * Convert an XLogRecPtr to a "usable byte position".
    1946             :  */
    1947             : static uint64
    1948        5176 : XLogRecPtrToBytePos(XLogRecPtr ptr)
    1949             : {
    1950             :     uint64      fullsegs;
    1951             :     uint32      fullpages;
    1952             :     uint32      offset;
    1953             :     uint64      result;
    1954             : 
    1955        5176 :     XLByteToSeg(ptr, fullsegs, wal_segment_size);
    1956             : 
    1957        5176 :     fullpages = (XLogSegmentOffset(ptr, wal_segment_size)) / XLOG_BLCKSZ;
    1958        5176 :     offset = ptr % XLOG_BLCKSZ;
    1959             : 
    1960        5176 :     if (fullpages == 0)
    1961             :     {
    1962        2038 :         result = fullsegs * UsableBytesInSegment;
    1963        2038 :         if (offset > 0)
    1964             :         {
    1965             :             Assert(offset >= SizeOfXLogLongPHD);
    1966         538 :             result += offset - SizeOfXLogLongPHD;
    1967             :         }
    1968             :     }
    1969             :     else
    1970             :     {
    1971        3138 :         result = fullsegs * UsableBytesInSegment +
    1972        3138 :             (XLOG_BLCKSZ - SizeOfXLogLongPHD) + /* account for first page */
    1973        3138 :             (fullpages - 1) * UsableBytesInPage;    /* full pages */
    1974        3138 :         if (offset > 0)
    1975             :         {
    1976             :             Assert(offset >= SizeOfXLogShortPHD);
    1977        3118 :             result += offset - SizeOfXLogShortPHD;
    1978             :         }
    1979             :     }
    1980             : 
    1981        5176 :     return result;
    1982             : }
    1983             : 
    1984             : /*
    1985             :  * Initialize XLOG buffers, writing out old buffers if they still contain
    1986             :  * unwritten data, upto the page containing 'upto'. Or if 'opportunistic' is
    1987             :  * true, initialize as many pages as we can without having to write out
    1988             :  * unwritten data. Any new pages are initialized to zeros, with pages headers
    1989             :  * initialized properly.
    1990             :  */
    1991             : static void
    1992     5339422 : AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli, bool opportunistic)
    1993             : {
    1994     5339422 :     XLogCtlInsert *Insert = &XLogCtl->Insert;
    1995             :     int         nextidx;
    1996             :     XLogRecPtr  OldPageRqstPtr;
    1997             :     XLogwrtRqst WriteRqst;
    1998     5339422 :     XLogRecPtr  NewPageEndPtr = InvalidXLogRecPtr;
    1999             :     XLogRecPtr  NewPageBeginPtr;
    2000             :     XLogPageHeader NewPage;
    2001     5339422 :     int         npages pg_attribute_unused() = 0;
    2002             : 
    2003     5339422 :     LWLockAcquire(WALBufMappingLock, LW_EXCLUSIVE);
    2004             : 
    2005             :     /*
    2006             :      * Now that we have the lock, check if someone initialized the page
    2007             :      * already.
    2008             :      */
    2009    15092256 :     while (upto >= XLogCtl->InitializedUpTo || opportunistic)
    2010             :     {
    2011     9762152 :         nextidx = XLogRecPtrToBufIdx(XLogCtl->InitializedUpTo);
    2012             : 
    2013             :         /*
    2014             :          * Get ending-offset of the buffer page we need to replace (this may
    2015             :          * be zero if the buffer hasn't been used yet).  Fall through if it's
    2016             :          * already written out.
    2017             :          */
    2018     9762152 :         OldPageRqstPtr = pg_atomic_read_u64(&XLogCtl->xlblocks[nextidx]);
    2019     9762152 :         if (LogwrtResult.Write < OldPageRqstPtr)
    2020             :         {
    2021             :             /*
    2022             :              * Nope, got work to do. If we just want to pre-initialize as much
    2023             :              * as we can without flushing, give up now.
    2024             :              */
    2025     4718686 :             if (opportunistic)
    2026        9318 :                 break;
    2027             : 
    2028             :             /* Advance shared memory write request position */
    2029     4709368 :             SpinLockAcquire(&XLogCtl->info_lck);
    2030     4709368 :             if (XLogCtl->LogwrtRqst.Write < OldPageRqstPtr)
    2031     1282456 :                 XLogCtl->LogwrtRqst.Write = OldPageRqstPtr;
    2032     4709368 :             SpinLockRelease(&XLogCtl->info_lck);
    2033             : 
    2034             :             /*
    2035             :              * Acquire an up-to-date LogwrtResult value and see if we still
    2036             :              * need to write it or if someone else already did.
    2037             :              */
    2038     4709368 :             RefreshXLogWriteResult(LogwrtResult);
    2039     4709368 :             if (LogwrtResult.Write < OldPageRqstPtr)
    2040             :             {
    2041             :                 /*
    2042             :                  * Must acquire write lock. Release WALBufMappingLock first,
    2043             :                  * to make sure that all insertions that we need to wait for
    2044             :                  * can finish (up to this same position). Otherwise we risk
    2045             :                  * deadlock.
    2046             :                  */
    2047     4590880 :                 LWLockRelease(WALBufMappingLock);
    2048             : 
    2049     4590880 :                 WaitXLogInsertionsToFinish(OldPageRqstPtr);
    2050             : 
    2051     4590880 :                 LWLockAcquire(WALWriteLock, LW_EXCLUSIVE);
    2052             : 
    2053     4590880 :                 RefreshXLogWriteResult(LogwrtResult);
    2054     4590880 :                 if (LogwrtResult.Write >= OldPageRqstPtr)
    2055             :                 {
    2056             :                     /* OK, someone wrote it already */
    2057      565746 :                     LWLockRelease(WALWriteLock);
    2058             :                 }
    2059             :                 else
    2060             :                 {
    2061             :                     /* Have to write it ourselves */
    2062             :                     TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_START();
    2063     4025134 :                     WriteRqst.Write = OldPageRqstPtr;
    2064     4025134 :                     WriteRqst.Flush = 0;
    2065     4025134 :                     XLogWrite(WriteRqst, tli, false);
    2066     4025134 :                     LWLockRelease(WALWriteLock);
    2067     4025134 :                     pgWalUsage.wal_buffers_full++;
    2068             :                     TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_DONE();
    2069             : 
    2070             :                     /*
    2071             :                      * Required for the flush of pending stats WAL data, per
    2072             :                      * update of pgWalUsage.
    2073             :                      */
    2074     4025134 :                     pgstat_report_fixed = true;
    2075             :                 }
    2076             :                 /* Re-acquire WALBufMappingLock and retry */
    2077     4590880 :                 LWLockAcquire(WALBufMappingLock, LW_EXCLUSIVE);
    2078     4590880 :                 continue;
    2079             :             }
    2080             :         }
    2081             : 
    2082             :         /*
    2083             :          * Now the next buffer slot is free and we can set it up to be the
    2084             :          * next output page.
    2085             :          */
    2086     5161954 :         NewPageBeginPtr = XLogCtl->InitializedUpTo;
    2087     5161954 :         NewPageEndPtr = NewPageBeginPtr + XLOG_BLCKSZ;
    2088             : 
    2089             :         Assert(XLogRecPtrToBufIdx(NewPageBeginPtr) == nextidx);
    2090             : 
    2091     5161954 :         NewPage = (XLogPageHeader) (XLogCtl->pages + nextidx * (Size) XLOG_BLCKSZ);
    2092             : 
    2093             :         /*
    2094             :          * Mark the xlblock with InvalidXLogRecPtr and issue a write barrier
    2095             :          * before initializing. Otherwise, the old page may be partially
    2096             :          * zeroed but look valid.
    2097             :          */
    2098     5161954 :         pg_atomic_write_u64(&XLogCtl->xlblocks[nextidx], InvalidXLogRecPtr);
    2099     5161954 :         pg_write_barrier();
    2100             : 
    2101             :         /*
    2102             :          * Be sure to re-zero the buffer so that bytes beyond what we've
    2103             :          * written will look like zeroes and not valid XLOG records...
    2104             :          */
    2105     5161954 :         MemSet(NewPage, 0, XLOG_BLCKSZ);
    2106             : 
    2107             :         /*
    2108             :          * Fill the new page's header
    2109             :          */
    2110     5161954 :         NewPage->xlp_magic = XLOG_PAGE_MAGIC;
    2111             : 
    2112             :         /* NewPage->xlp_info = 0; */ /* done by memset */
    2113     5161954 :         NewPage->xlp_tli = tli;
    2114     5161954 :         NewPage->xlp_pageaddr = NewPageBeginPtr;
    2115             : 
    2116             :         /* NewPage->xlp_rem_len = 0; */  /* done by memset */
    2117             : 
    2118             :         /*
    2119             :          * If online backup is not in progress, mark the header to indicate
    2120             :          * that WAL records beginning in this page have removable backup
    2121             :          * blocks.  This allows the WAL archiver to know whether it is safe to
    2122             :          * compress archived WAL data by transforming full-block records into
    2123             :          * the non-full-block format.  It is sufficient to record this at the
    2124             :          * page level because we force a page switch (in fact a segment
    2125             :          * switch) when starting a backup, so the flag will be off before any
    2126             :          * records can be written during the backup.  At the end of a backup,
    2127             :          * the last page will be marked as all unsafe when perhaps only part
    2128             :          * is unsafe, but at worst the archiver would miss the opportunity to
    2129             :          * compress a few records.
    2130             :          */
    2131     5161954 :         if (Insert->runningBackups == 0)
    2132     4890738 :             NewPage->xlp_info |= XLP_BKP_REMOVABLE;
    2133             : 
    2134             :         /*
    2135             :          * If first page of an XLOG segment file, make it a long header.
    2136             :          */
    2137     5161954 :         if ((XLogSegmentOffset(NewPage->xlp_pageaddr, wal_segment_size)) == 0)
    2138             :         {
    2139        3630 :             XLogLongPageHeader NewLongPage = (XLogLongPageHeader) NewPage;
    2140             : 
    2141        3630 :             NewLongPage->xlp_sysid = ControlFile->system_identifier;
    2142        3630 :             NewLongPage->xlp_seg_size = wal_segment_size;
    2143        3630 :             NewLongPage->xlp_xlog_blcksz = XLOG_BLCKSZ;
    2144        3630 :             NewPage->xlp_info |= XLP_LONG_HEADER;
    2145             :         }
    2146             : 
    2147             :         /*
    2148             :          * Make sure the initialization of the page becomes visible to others
    2149             :          * before the xlblocks update. GetXLogBuffer() reads xlblocks without
    2150             :          * holding a lock.
    2151             :          */
    2152     5161954 :         pg_write_barrier();
    2153             : 
    2154     5161954 :         pg_atomic_write_u64(&XLogCtl->xlblocks[nextidx], NewPageEndPtr);
    2155     5161954 :         XLogCtl->InitializedUpTo = NewPageEndPtr;
    2156             : 
    2157     5161954 :         npages++;
    2158             :     }
    2159     5339422 :     LWLockRelease(WALBufMappingLock);
    2160             : 
    2161             : #ifdef WAL_DEBUG
    2162             :     if (XLOG_DEBUG && npages > 0)
    2163             :     {
    2164             :         elog(DEBUG1, "initialized %d pages, up to %X/%08X",
    2165             :              npages, LSN_FORMAT_ARGS(NewPageEndPtr));
    2166             :     }
    2167             : #endif
    2168     5339422 : }
    2169             : 
    2170             : /*
    2171             :  * Calculate CheckPointSegments based on max_wal_size_mb and
    2172             :  * checkpoint_completion_target.
    2173             :  */
    2174             : static void
    2175       16172 : CalculateCheckpointSegments(void)
    2176             : {
    2177             :     double      target;
    2178             : 
    2179             :     /*-------
    2180             :      * Calculate the distance at which to trigger a checkpoint, to avoid
    2181             :      * exceeding max_wal_size_mb. This is based on two assumptions:
    2182             :      *
    2183             :      * a) we keep WAL for only one checkpoint cycle (prior to PG11 we kept
    2184             :      *    WAL for two checkpoint cycles to allow us to recover from the
    2185             :      *    secondary checkpoint if the first checkpoint failed, though we
    2186             :      *    only did this on the primary anyway, not on standby. Keeping just
    2187             :      *    one checkpoint simplifies processing and reduces disk space in
    2188             :      *    many smaller databases.)
    2189             :      * b) during checkpoint, we consume checkpoint_completion_target *
    2190             :      *    number of segments consumed between checkpoints.
    2191             :      *-------
    2192             :      */
    2193       16172 :     target = (double) ConvertToXSegs(max_wal_size_mb, wal_segment_size) /
    2194       16172 :         (1.0 + CheckPointCompletionTarget);
    2195             : 
    2196             :     /* round down */
    2197       16172 :     CheckPointSegments = (int) target;
    2198             : 
    2199       16172 :     if (CheckPointSegments < 1)
    2200          20 :         CheckPointSegments = 1;
    2201       16172 : }
    2202             : 
    2203             : void
    2204       11742 : assign_max_wal_size(int newval, void *extra)
    2205             : {
    2206       11742 :     max_wal_size_mb = newval;
    2207       11742 :     CalculateCheckpointSegments();
    2208       11742 : }
    2209             : 
    2210             : void
    2211        2346 : assign_checkpoint_completion_target(double newval, void *extra)
    2212             : {
    2213        2346 :     CheckPointCompletionTarget = newval;
    2214        2346 :     CalculateCheckpointSegments();
    2215        2346 : }
    2216             : 
    2217             : bool
    2218        4534 : check_wal_segment_size(int *newval, void **extra, GucSource source)
    2219             : {
    2220        4534 :     if (!IsValidWalSegSize(*newval))
    2221             :     {
    2222           0 :         GUC_check_errdetail("The WAL segment size must be a power of two between 1 MB and 1 GB.");
    2223           0 :         return false;
    2224             :     }
    2225             : 
    2226        4534 :     return true;
    2227             : }
    2228             : 
    2229             : /*
    2230             :  * At a checkpoint, how many WAL segments to recycle as preallocated future
    2231             :  * XLOG segments? Returns the highest segment that should be preallocated.
    2232             :  */
    2233             : static XLogSegNo
    2234        3550 : XLOGfileslop(XLogRecPtr lastredoptr)
    2235             : {
    2236             :     XLogSegNo   minSegNo;
    2237             :     XLogSegNo   maxSegNo;
    2238             :     double      distance;
    2239             :     XLogSegNo   recycleSegNo;
    2240             : 
    2241             :     /*
    2242             :      * Calculate the segment numbers that min_wal_size_mb and max_wal_size_mb
    2243             :      * correspond to. Always recycle enough segments to meet the minimum, and
    2244             :      * remove enough segments to stay below the maximum.
    2245             :      */
    2246        3550 :     minSegNo = lastredoptr / wal_segment_size +
    2247        3550 :         ConvertToXSegs(min_wal_size_mb, wal_segment_size) - 1;
    2248        3550 :     maxSegNo = lastredoptr / wal_segment_size +
    2249        3550 :         ConvertToXSegs(max_wal_size_mb, wal_segment_size) - 1;
    2250             : 
    2251             :     /*
    2252             :      * Between those limits, recycle enough segments to get us through to the
    2253             :      * estimated end of next checkpoint.
    2254             :      *
    2255             :      * To estimate where the next checkpoint will finish, assume that the
    2256             :      * system runs steadily consuming CheckPointDistanceEstimate bytes between
    2257             :      * every checkpoint.
    2258             :      */
    2259        3550 :     distance = (1.0 + CheckPointCompletionTarget) * CheckPointDistanceEstimate;
    2260             :     /* add 10% for good measure. */
    2261        3550 :     distance *= 1.10;
    2262             : 
    2263        3550 :     recycleSegNo = (XLogSegNo) ceil(((double) lastredoptr + distance) /
    2264             :                                     wal_segment_size);
    2265             : 
    2266        3550 :     if (recycleSegNo < minSegNo)
    2267        2518 :         recycleSegNo = minSegNo;
    2268        3550 :     if (recycleSegNo > maxSegNo)
    2269         788 :         recycleSegNo = maxSegNo;
    2270             : 
    2271        3550 :     return recycleSegNo;
    2272             : }
    2273             : 
    2274             : /*
    2275             :  * Check whether we've consumed enough xlog space that a checkpoint is needed.
    2276             :  *
    2277             :  * new_segno indicates a log file that has just been filled up (or read
    2278             :  * during recovery). We measure the distance from RedoRecPtr to new_segno
    2279             :  * and see if that exceeds CheckPointSegments.
    2280             :  *
    2281             :  * Note: it is caller's responsibility that RedoRecPtr is up-to-date.
    2282             :  */
    2283             : bool
    2284       10156 : XLogCheckpointNeeded(XLogSegNo new_segno)
    2285             : {
    2286             :     XLogSegNo   old_segno;
    2287             : 
    2288       10156 :     XLByteToSeg(RedoRecPtr, old_segno, wal_segment_size);
    2289             : 
    2290       10156 :     if (new_segno >= old_segno + (uint64) (CheckPointSegments - 1))
    2291        6580 :         return true;
    2292        3576 :     return false;
    2293             : }
    2294             : 
    2295             : /*
    2296             :  * Write and/or fsync the log at least as far as WriteRqst indicates.
    2297             :  *
    2298             :  * If flexible == true, we don't have to write as far as WriteRqst, but
    2299             :  * may stop at any convenient boundary (such as a cache or logfile boundary).
    2300             :  * This option allows us to avoid uselessly issuing multiple writes when a
    2301             :  * single one would do.
    2302             :  *
    2303             :  * Must be called with WALWriteLock held. WaitXLogInsertionsToFinish(WriteRqst)
    2304             :  * must be called before grabbing the lock, to make sure the data is ready to
    2305             :  * write.
    2306             :  */
    2307             : static void
    2308     4300196 : XLogWrite(XLogwrtRqst WriteRqst, TimeLineID tli, bool flexible)
    2309             : {
    2310             :     bool        ispartialpage;
    2311             :     bool        last_iteration;
    2312             :     bool        finishing_seg;
    2313             :     int         curridx;
    2314             :     int         npages;
    2315             :     int         startidx;
    2316             :     uint32      startoffset;
    2317             : 
    2318             :     /* We should always be inside a critical section here */
    2319             :     Assert(CritSectionCount > 0);
    2320             : 
    2321             :     /*
    2322             :      * Update local LogwrtResult (caller probably did this already, but...)
    2323             :      */
    2324     4300196 :     RefreshXLogWriteResult(LogwrtResult);
    2325             : 
    2326             :     /*
    2327             :      * Since successive pages in the xlog cache are consecutively allocated,
    2328             :      * we can usually gather multiple pages together and issue just one
    2329             :      * write() call.  npages is the number of pages we have determined can be
    2330             :      * written together; startidx is the cache block index of the first one,
    2331             :      * and startoffset is the file offset at which it should go. The latter
    2332             :      * two variables are only valid when npages > 0, but we must initialize
    2333             :      * all of them to keep the compiler quiet.
    2334             :      */
    2335     4300196 :     npages = 0;
    2336     4300196 :     startidx = 0;
    2337     4300196 :     startoffset = 0;
    2338             : 
    2339             :     /*
    2340             :      * Within the loop, curridx is the cache block index of the page to
    2341             :      * consider writing.  Begin at the buffer containing the next unwritten
    2342             :      * page, or last partially written page.
    2343             :      */
    2344     4300196 :     curridx = XLogRecPtrToBufIdx(LogwrtResult.Write);
    2345             : 
    2346     9333506 :     while (LogwrtResult.Write < WriteRqst.Write)
    2347             :     {
    2348             :         /*
    2349             :          * Make sure we're not ahead of the insert process.  This could happen
    2350             :          * if we're passed a bogus WriteRqst.Write that is past the end of the
    2351             :          * last page that's been initialized by AdvanceXLInsertBuffer.
    2352             :          */
    2353     5299064 :         XLogRecPtr  EndPtr = pg_atomic_read_u64(&XLogCtl->xlblocks[curridx]);
    2354             : 
    2355     5299064 :         if (LogwrtResult.Write >= EndPtr)
    2356           0 :             elog(PANIC, "xlog write request %X/%08X is past end of log %X/%08X",
    2357             :                  LSN_FORMAT_ARGS(LogwrtResult.Write),
    2358             :                  LSN_FORMAT_ARGS(EndPtr));
    2359             : 
    2360             :         /* Advance LogwrtResult.Write to end of current buffer page */
    2361     5299064 :         LogwrtResult.Write = EndPtr;
    2362     5299064 :         ispartialpage = WriteRqst.Write < LogwrtResult.Write;
    2363             : 
    2364     5299064 :         if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo,
    2365             :                              wal_segment_size))
    2366             :         {
    2367             :             /*
    2368             :              * Switch to new logfile segment.  We cannot have any pending
    2369             :              * pages here (since we dump what we have at segment end).
    2370             :              */
    2371             :             Assert(npages == 0);
    2372       27278 :             if (openLogFile >= 0)
    2373       12180 :                 XLogFileClose();
    2374       27278 :             XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
    2375             :                             wal_segment_size);
    2376       27278 :             openLogTLI = tli;
    2377             : 
    2378             :             /* create/use new log file */
    2379       27278 :             openLogFile = XLogFileInit(openLogSegNo, tli);
    2380       27278 :             ReserveExternalFD();
    2381             :         }
    2382             : 
    2383             :         /* Make sure we have the current logfile open */
    2384     5299064 :         if (openLogFile < 0)
    2385             :         {
    2386           0 :             XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
    2387             :                             wal_segment_size);
    2388           0 :             openLogTLI = tli;
    2389           0 :             openLogFile = XLogFileOpen(openLogSegNo, tli);
    2390           0 :             ReserveExternalFD();
    2391             :         }
    2392             : 
    2393             :         /* Add current page to the set of pending pages-to-dump */
    2394     5299064 :         if (npages == 0)
    2395             :         {
    2396             :             /* first of group */
    2397     4331158 :             startidx = curridx;
    2398     4331158 :             startoffset = XLogSegmentOffset(LogwrtResult.Write - XLOG_BLCKSZ,
    2399             :                                             wal_segment_size);
    2400             :         }
    2401     5299064 :         npages++;
    2402             : 
    2403             :         /*
    2404             :          * Dump the set if this will be the last loop iteration, or if we are
    2405             :          * at the last page of the cache area (since the next page won't be
    2406             :          * contiguous in memory), or if we are at the end of the logfile
    2407             :          * segment.
    2408             :          */
    2409     5299064 :         last_iteration = WriteRqst.Write <= LogwrtResult.Write;
    2410             : 
    2411    10339734 :         finishing_seg = !ispartialpage &&
    2412     5040670 :             (startoffset + npages * XLOG_BLCKSZ) >= wal_segment_size;
    2413             : 
    2414     5299064 :         if (last_iteration ||
    2415     1000706 :             curridx == XLogCtl->XLogCacheBlck ||
    2416             :             finishing_seg)
    2417             :         {
    2418             :             char       *from;
    2419             :             Size        nbytes;
    2420             :             Size        nleft;
    2421             :             ssize_t     written;
    2422             :             instr_time  start;
    2423             : 
    2424             :             /* OK to write the page(s) */
    2425     4331158 :             from = XLogCtl->pages + startidx * (Size) XLOG_BLCKSZ;
    2426     4331158 :             nbytes = npages * (Size) XLOG_BLCKSZ;
    2427     4331158 :             nleft = nbytes;
    2428             :             do
    2429             :             {
    2430     4331158 :                 errno = 0;
    2431             : 
    2432             :                 /*
    2433             :                  * Measure I/O timing to write WAL data, for pg_stat_io.
    2434             :                  */
    2435     4331158 :                 start = pgstat_prepare_io_time(track_wal_io_timing);
    2436             : 
    2437     4331158 :                 pgstat_report_wait_start(WAIT_EVENT_WAL_WRITE);
    2438     4331158 :                 written = pg_pwrite(openLogFile, from, nleft, startoffset);
    2439     4331158 :                 pgstat_report_wait_end();
    2440             : 
    2441     4331158 :                 pgstat_count_io_op_time(IOOBJECT_WAL, IOCONTEXT_NORMAL,
    2442             :                                         IOOP_WRITE, start, 1, written);
    2443             : 
    2444     4331158 :                 if (written <= 0)
    2445             :                 {
    2446             :                     char        xlogfname[MAXFNAMELEN];
    2447             :                     int         save_errno;
    2448             : 
    2449           0 :                     if (errno == EINTR)
    2450           0 :                         continue;
    2451             : 
    2452           0 :                     save_errno = errno;
    2453           0 :                     XLogFileName(xlogfname, tli, openLogSegNo,
    2454             :                                  wal_segment_size);
    2455           0 :                     errno = save_errno;
    2456           0 :                     ereport(PANIC,
    2457             :                             (errcode_for_file_access(),
    2458             :                              errmsg("could not write to log file \"%s\" at offset %u, length %zu: %m",
    2459             :                                     xlogfname, startoffset, nleft)));
    2460             :                 }
    2461     4331158 :                 nleft -= written;
    2462     4331158 :                 from += written;
    2463     4331158 :                 startoffset += written;
    2464     4331158 :             } while (nleft > 0);
    2465             : 
    2466     4331158 :             npages = 0;
    2467             : 
    2468             :             /*
    2469             :              * If we just wrote the whole last page of a logfile segment,
    2470             :              * fsync the segment immediately.  This avoids having to go back
    2471             :              * and re-open prior segments when an fsync request comes along
    2472             :              * later. Doing it here ensures that one and only one backend will
    2473             :              * perform this fsync.
    2474             :              *
    2475             :              * This is also the right place to notify the Archiver that the
    2476             :              * segment is ready to copy to archival storage, and to update the
    2477             :              * timer for archive_timeout, and to signal for a checkpoint if
    2478             :              * too many logfile segments have been used since the last
    2479             :              * checkpoint.
    2480             :              */
    2481     4331158 :             if (finishing_seg)
    2482             :             {
    2483        3836 :                 issue_xlog_fsync(openLogFile, openLogSegNo, tli);
    2484             : 
    2485             :                 /* signal that we need to wakeup walsenders later */
    2486        3836 :                 WalSndWakeupRequest();
    2487             : 
    2488        3836 :                 LogwrtResult.Flush = LogwrtResult.Write;    /* end of page */
    2489             : 
    2490        3836 :                 if (XLogArchivingActive())
    2491         812 :                     XLogArchiveNotifySeg(openLogSegNo, tli);
    2492             : 
    2493        3836 :                 XLogCtl->lastSegSwitchTime = (pg_time_t) time(NULL);
    2494        3836 :                 XLogCtl->lastSegSwitchLSN = LogwrtResult.Flush;
    2495             : 
    2496             :                 /*
    2497             :                  * Request a checkpoint if we've consumed too much xlog since
    2498             :                  * the last one.  For speed, we first check using the local
    2499             :                  * copy of RedoRecPtr, which might be out of date; if it looks
    2500             :                  * like a checkpoint is needed, forcibly update RedoRecPtr and
    2501             :                  * recheck.
    2502             :                  */
    2503        3836 :                 if (IsUnderPostmaster && XLogCheckpointNeeded(openLogSegNo))
    2504             :                 {
    2505         508 :                     (void) GetRedoRecPtr();
    2506         508 :                     if (XLogCheckpointNeeded(openLogSegNo))
    2507         406 :                         RequestCheckpoint(CHECKPOINT_CAUSE_XLOG);
    2508             :                 }
    2509             :             }
    2510             :         }
    2511             : 
    2512     5299064 :         if (ispartialpage)
    2513             :         {
    2514             :             /* Only asked to write a partial page */
    2515      258394 :             LogwrtResult.Write = WriteRqst.Write;
    2516      258394 :             break;
    2517             :         }
    2518     5040670 :         curridx = NextBufIdx(curridx);
    2519             : 
    2520             :         /* If flexible, break out of loop as soon as we wrote something */
    2521     5040670 :         if (flexible && npages == 0)
    2522        7360 :             break;
    2523             :     }
    2524             : 
    2525             :     Assert(npages == 0);
    2526             : 
    2527             :     /*
    2528             :      * If asked to flush, do so
    2529             :      */
    2530     4300196 :     if (LogwrtResult.Flush < WriteRqst.Flush &&
    2531      273570 :         LogwrtResult.Flush < LogwrtResult.Write)
    2532             :     {
    2533             :         /*
    2534             :          * Could get here without iterating above loop, in which case we might
    2535             :          * have no open file or the wrong one.  However, we do not need to
    2536             :          * fsync more than one file.
    2537             :          */
    2538      273428 :         if (wal_sync_method != WAL_SYNC_METHOD_OPEN &&
    2539      273428 :             wal_sync_method != WAL_SYNC_METHOD_OPEN_DSYNC)
    2540             :         {
    2541      273428 :             if (openLogFile >= 0 &&
    2542      273418 :                 !XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo,
    2543             :                                  wal_segment_size))
    2544         136 :                 XLogFileClose();
    2545      273428 :             if (openLogFile < 0)
    2546             :             {
    2547         146 :                 XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
    2548             :                                 wal_segment_size);
    2549         146 :                 openLogTLI = tli;
    2550         146 :                 openLogFile = XLogFileOpen(openLogSegNo, tli);
    2551         146 :                 ReserveExternalFD();
    2552             :             }
    2553             : 
    2554      273428 :             issue_xlog_fsync(openLogFile, openLogSegNo, tli);
    2555             :         }
    2556             : 
    2557             :         /* signal that we need to wakeup walsenders later */
    2558      273428 :         WalSndWakeupRequest();
    2559             : 
    2560      273428 :         LogwrtResult.Flush = LogwrtResult.Write;
    2561             :     }
    2562             : 
    2563             :     /*
    2564             :      * Update shared-memory status
    2565             :      *
    2566             :      * We make sure that the shared 'request' values do not fall behind the
    2567             :      * 'result' values.  This is not absolutely essential, but it saves some
    2568             :      * code in a couple of places.
    2569             :      */
    2570     4300196 :     SpinLockAcquire(&XLogCtl->info_lck);
    2571     4300196 :     if (XLogCtl->LogwrtRqst.Write < LogwrtResult.Write)
    2572      238928 :         XLogCtl->LogwrtRqst.Write = LogwrtResult.Write;
    2573     4300196 :     if (XLogCtl->LogwrtRqst.Flush < LogwrtResult.Flush)
    2574      276484 :         XLogCtl->LogwrtRqst.Flush = LogwrtResult.Flush;
    2575     4300196 :     SpinLockRelease(&XLogCtl->info_lck);
    2576             : 
    2577             :     /*
    2578             :      * We write Write first, bar, then Flush.  When reading, the opposite must
    2579             :      * be done (with a matching barrier in between), so that we always see a
    2580             :      * Flush value that trails behind the Write value seen.
    2581             :      */
    2582     4300196 :     pg_atomic_write_u64(&XLogCtl->logWriteResult, LogwrtResult.Write);
    2583     4300196 :     pg_write_barrier();
    2584     4300196 :     pg_atomic_write_u64(&XLogCtl->logFlushResult, LogwrtResult.Flush);
    2585             : 
    2586             : #ifdef USE_ASSERT_CHECKING
    2587             :     {
    2588             :         XLogRecPtr  Flush;
    2589             :         XLogRecPtr  Write;
    2590             :         XLogRecPtr  Insert;
    2591             : 
    2592             :         Flush = pg_atomic_read_u64(&XLogCtl->logFlushResult);
    2593             :         pg_read_barrier();
    2594             :         Write = pg_atomic_read_u64(&XLogCtl->logWriteResult);
    2595             :         pg_read_barrier();
    2596             :         Insert = pg_atomic_read_u64(&XLogCtl->logInsertResult);
    2597             : 
    2598             :         /* WAL written to disk is always ahead of WAL flushed */
    2599             :         Assert(Write >= Flush);
    2600             : 
    2601             :         /* WAL inserted to buffers is always ahead of WAL written */
    2602             :         Assert(Insert >= Write);
    2603             :     }
    2604             : #endif
    2605     4300196 : }
    2606             : 
    2607             : /*
    2608             :  * Record the LSN for an asynchronous transaction commit/abort
    2609             :  * and nudge the WALWriter if there is work for it to do.
    2610             :  * (This should not be called for synchronous commits.)
    2611             :  */
    2612             : void
    2613      102108 : XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN)
    2614             : {
    2615      102108 :     XLogRecPtr  WriteRqstPtr = asyncXactLSN;
    2616             :     bool        sleeping;
    2617      102108 :     bool        wakeup = false;
    2618             :     XLogRecPtr  prevAsyncXactLSN;
    2619             : 
    2620      102108 :     SpinLockAcquire(&XLogCtl->info_lck);
    2621      102108 :     sleeping = XLogCtl->WalWriterSleeping;
    2622      102108 :     prevAsyncXactLSN = XLogCtl->asyncXactLSN;
    2623      102108 :     if (XLogCtl->asyncXactLSN < asyncXactLSN)
    2624      101118 :         XLogCtl->asyncXactLSN = asyncXactLSN;
    2625      102108 :     SpinLockRelease(&XLogCtl->info_lck);
    2626             : 
    2627             :     /*
    2628             :      * If somebody else already called this function with a more aggressive
    2629             :      * LSN, they will have done what we needed (and perhaps more).
    2630             :      */
    2631      102108 :     if (asyncXactLSN <= prevAsyncXactLSN)
    2632         990 :         return;
    2633             : 
    2634             :     /*
    2635             :      * If the WALWriter is sleeping, kick it to make it come out of low-power
    2636             :      * mode, so that this async commit will reach disk within the expected
    2637             :      * amount of time.  Otherwise, determine whether it has enough WAL
    2638             :      * available to flush, the same way that XLogBackgroundFlush() does.
    2639             :      */
    2640      101118 :     if (sleeping)
    2641          40 :         wakeup = true;
    2642             :     else
    2643             :     {
    2644             :         int         flushblocks;
    2645             : 
    2646      101078 :         RefreshXLogWriteResult(LogwrtResult);
    2647             : 
    2648      101078 :         flushblocks =
    2649      101078 :             WriteRqstPtr / XLOG_BLCKSZ - LogwrtResult.Flush / XLOG_BLCKSZ;
    2650             : 
    2651      101078 :         if (WalWriterFlushAfter == 0 || flushblocks >= WalWriterFlushAfter)
    2652        7632 :             wakeup = true;
    2653             :     }
    2654             : 
    2655      101118 :     if (wakeup)
    2656             :     {
    2657        7672 :         volatile PROC_HDR *procglobal = ProcGlobal;
    2658        7672 :         ProcNumber  walwriterProc = procglobal->walwriterProc;
    2659             : 
    2660        7672 :         if (walwriterProc != INVALID_PROC_NUMBER)
    2661         448 :             SetLatch(&GetPGProcByNumber(walwriterProc)->procLatch);
    2662             :     }
    2663             : }
    2664             : 
    2665             : /*
    2666             :  * Record the LSN up to which we can remove WAL because it's not required by
    2667             :  * any replication slot.
    2668             :  */
    2669             : void
    2670       50072 : XLogSetReplicationSlotMinimumLSN(XLogRecPtr lsn)
    2671             : {
    2672       50072 :     SpinLockAcquire(&XLogCtl->info_lck);
    2673       50072 :     XLogCtl->replicationSlotMinLSN = lsn;
    2674       50072 :     SpinLockRelease(&XLogCtl->info_lck);
    2675       50072 : }
    2676             : 
    2677             : 
    2678             : /*
    2679             :  * Return the oldest LSN we must retain to satisfy the needs of some
    2680             :  * replication slot.
    2681             :  */
    2682             : static XLogRecPtr
    2683        4570 : XLogGetReplicationSlotMinimumLSN(void)
    2684             : {
    2685             :     XLogRecPtr  retval;
    2686             : 
    2687        4570 :     SpinLockAcquire(&XLogCtl->info_lck);
    2688        4570 :     retval = XLogCtl->replicationSlotMinLSN;
    2689        4570 :     SpinLockRelease(&XLogCtl->info_lck);
    2690             : 
    2691        4570 :     return retval;
    2692             : }
    2693             : 
    2694             : /*
    2695             :  * Advance minRecoveryPoint in control file.
    2696             :  *
    2697             :  * If we crash during recovery, we must reach this point again before the
    2698             :  * database is consistent.
    2699             :  *
    2700             :  * If 'force' is true, 'lsn' argument is ignored. Otherwise, minRecoveryPoint
    2701             :  * is only updated if it's not already greater than or equal to 'lsn'.
    2702             :  */
    2703             : static void
    2704      213792 : UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
    2705             : {
    2706             :     /* Quick check using our local copy of the variable */
    2707      213792 :     if (!updateMinRecoveryPoint || (!force && lsn <= LocalMinRecoveryPoint))
    2708      200368 :         return;
    2709             : 
    2710             :     /*
    2711             :      * An invalid minRecoveryPoint means that we need to recover all the WAL,
    2712             :      * i.e., we're doing crash recovery.  We never modify the control file's
    2713             :      * value in that case, so we can short-circuit future checks here too. The
    2714             :      * local values of minRecoveryPoint and minRecoveryPointTLI should not be
    2715             :      * updated until crash recovery finishes.  We only do this for the startup
    2716             :      * process as it should not update its own reference of minRecoveryPoint
    2717             :      * until it has finished crash recovery to make sure that all WAL
    2718             :      * available is replayed in this case.  This also saves from extra locks
    2719             :      * taken on the control file from the startup process.
    2720             :      */
    2721       13424 :     if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
    2722             :     {
    2723          60 :         updateMinRecoveryPoint = false;
    2724          60 :         return;
    2725             :     }
    2726             : 
    2727       13364 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    2728             : 
    2729             :     /* update local copy */
    2730       13364 :     LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
    2731       13364 :     LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
    2732             : 
    2733       13364 :     if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
    2734           4 :         updateMinRecoveryPoint = false;
    2735       13360 :     else if (force || LocalMinRecoveryPoint < lsn)
    2736             :     {
    2737             :         XLogRecPtr  newMinRecoveryPoint;
    2738             :         TimeLineID  newMinRecoveryPointTLI;
    2739             : 
    2740             :         /*
    2741             :          * To avoid having to update the control file too often, we update it
    2742             :          * all the way to the last record being replayed, even though 'lsn'
    2743             :          * would suffice for correctness.  This also allows the 'force' case
    2744             :          * to not need a valid 'lsn' value.
    2745             :          *
    2746             :          * Another important reason for doing it this way is that the passed
    2747             :          * 'lsn' value could be bogus, i.e., past the end of available WAL, if
    2748             :          * the caller got it from a corrupted heap page.  Accepting such a
    2749             :          * value as the min recovery point would prevent us from coming up at
    2750             :          * all.  Instead, we just log a warning and continue with recovery.
    2751             :          * (See also the comments about corrupt LSNs in XLogFlush.)
    2752             :          */
    2753       10978 :         newMinRecoveryPoint = GetCurrentReplayRecPtr(&newMinRecoveryPointTLI);
    2754       10978 :         if (!force && newMinRecoveryPoint < lsn)
    2755           0 :             elog(WARNING,
    2756             :                  "xlog min recovery request %X/%08X is past current point %X/%08X",
    2757             :                  LSN_FORMAT_ARGS(lsn), LSN_FORMAT_ARGS(newMinRecoveryPoint));
    2758             : 
    2759             :         /* update control file */
    2760       10978 :         if (ControlFile->minRecoveryPoint < newMinRecoveryPoint)
    2761             :         {
    2762       10278 :             ControlFile->minRecoveryPoint = newMinRecoveryPoint;
    2763       10278 :             ControlFile->minRecoveryPointTLI = newMinRecoveryPointTLI;
    2764       10278 :             UpdateControlFile();
    2765       10278 :             LocalMinRecoveryPoint = newMinRecoveryPoint;
    2766       10278 :             LocalMinRecoveryPointTLI = newMinRecoveryPointTLI;
    2767             : 
    2768       10278 :             ereport(DEBUG2,
    2769             :                     errmsg_internal("updated min recovery point to %X/%08X on timeline %u",
    2770             :                                     LSN_FORMAT_ARGS(newMinRecoveryPoint),
    2771             :                                     newMinRecoveryPointTLI));
    2772             :         }
    2773             :     }
    2774       13364 :     LWLockRelease(ControlFileLock);
    2775             : }
    2776             : 
    2777             : /*
    2778             :  * Ensure that all XLOG data through the given position is flushed to disk.
    2779             :  *
    2780             :  * NOTE: this differs from XLogWrite mainly in that the WALWriteLock is not
    2781             :  * already held, and we try to avoid acquiring it if possible.
    2782             :  */
    2783             : void
    2784     1398466 : XLogFlush(XLogRecPtr record)
    2785             : {
    2786             :     XLogRecPtr  WriteRqstPtr;
    2787             :     XLogwrtRqst WriteRqst;
    2788     1398466 :     TimeLineID  insertTLI = XLogCtl->InsertTimeLineID;
    2789             : 
    2790             :     /*
    2791             :      * During REDO, we are reading not writing WAL.  Therefore, instead of
    2792             :      * trying to flush the WAL, we should update minRecoveryPoint instead. We
    2793             :      * test XLogInsertAllowed(), not InRecovery, because we need checkpointer
    2794             :      * to act this way too, and because when it tries to write the
    2795             :      * end-of-recovery checkpoint, it should indeed flush.
    2796             :      */
    2797     1398466 :     if (!XLogInsertAllowed())
    2798             :     {
    2799      212914 :         UpdateMinRecoveryPoint(record, false);
    2800     1106458 :         return;
    2801             :     }
    2802             : 
    2803             :     /* Quick exit if already known flushed */
    2804     1185552 :     if (record <= LogwrtResult.Flush)
    2805      893544 :         return;
    2806             : 
    2807             : #ifdef WAL_DEBUG
    2808             :     if (XLOG_DEBUG)
    2809             :         elog(LOG, "xlog flush request %X/%08X; write %X/%08X; flush %X/%08X",
    2810             :              LSN_FORMAT_ARGS(record),
    2811             :              LSN_FORMAT_ARGS(LogwrtResult.Write),
    2812             :              LSN_FORMAT_ARGS(LogwrtResult.Flush));
    2813             : #endif
    2814             : 
    2815      292008 :     START_CRIT_SECTION();
    2816             : 
    2817             :     /*
    2818             :      * Since fsync is usually a horribly expensive operation, we try to
    2819             :      * piggyback as much data as we can on each fsync: if we see any more data
    2820             :      * entered into the xlog buffer, we'll write and fsync that too, so that
    2821             :      * the final value of LogwrtResult.Flush is as large as possible. This
    2822             :      * gives us some chance of avoiding another fsync immediately after.
    2823             :      */
    2824             : 
    2825             :     /* initialize to given target; may increase below */
    2826      292008 :     WriteRqstPtr = record;
    2827             : 
    2828             :     /*
    2829             :      * Now wait until we get the write lock, or someone else does the flush
    2830             :      * for us.
    2831             :      */
    2832             :     for (;;)
    2833        9914 :     {
    2834             :         XLogRecPtr  insertpos;
    2835             : 
    2836             :         /* done already? */
    2837      301922 :         RefreshXLogWriteResult(LogwrtResult);
    2838      301922 :         if (record <= LogwrtResult.Flush)
    2839       22034 :             break;
    2840             : 
    2841             :         /*
    2842             :          * Before actually performing the write, wait for all in-flight
    2843             :          * insertions to the pages we're about to write to finish.
    2844             :          */
    2845      279888 :         SpinLockAcquire(&XLogCtl->info_lck);
    2846      279888 :         if (WriteRqstPtr < XLogCtl->LogwrtRqst.Write)
    2847       19568 :             WriteRqstPtr = XLogCtl->LogwrtRqst.Write;
    2848      279888 :         SpinLockRelease(&XLogCtl->info_lck);
    2849      279888 :         insertpos = WaitXLogInsertionsToFinish(WriteRqstPtr);
    2850             : 
    2851             :         /*
    2852             :          * Try to get the write lock. If we can't get it immediately, wait
    2853             :          * until it's released, and recheck if we still need to do the flush
    2854             :          * or if the backend that held the lock did it for us already. This
    2855             :          * helps to maintain a good rate of group committing when the system
    2856             :          * is bottlenecked by the speed of fsyncing.
    2857             :          */
    2858      279888 :         if (!LWLockAcquireOrWait(WALWriteLock, LW_EXCLUSIVE))
    2859             :         {
    2860             :             /*
    2861             :              * The lock is now free, but we didn't acquire it yet. Before we
    2862             :              * do, loop back to check if someone else flushed the record for
    2863             :              * us already.
    2864             :              */
    2865        9914 :             continue;
    2866             :         }
    2867             : 
    2868             :         /* Got the lock; recheck whether request is satisfied */
    2869      269974 :         RefreshXLogWriteResult(LogwrtResult);
    2870      269974 :         if (record <= LogwrtResult.Flush)
    2871             :         {
    2872        3916 :             LWLockRelease(WALWriteLock);
    2873        3916 :             break;
    2874             :         }
    2875             : 
    2876             :         /*
    2877             :          * Sleep before flush! By adding a delay here, we may give further
    2878             :          * backends the opportunity to join the backlog of group commit
    2879             :          * followers; this can significantly improve transaction throughput,
    2880             :          * at the risk of increasing transaction latency.
    2881             :          *
    2882             :          * We do not sleep if enableFsync is not turned on, nor if there are
    2883             :          * fewer than CommitSiblings other backends with active transactions.
    2884             :          */
    2885      266058 :         if (CommitDelay > 0 && enableFsync &&
    2886           0 :             MinimumActiveBackends(CommitSiblings))
    2887             :         {
    2888           0 :             pgstat_report_wait_start(WAIT_EVENT_COMMIT_DELAY);
    2889           0 :             pg_usleep(CommitDelay);
    2890           0 :             pgstat_report_wait_end();
    2891             : 
    2892             :             /*
    2893             :              * Re-check how far we can now flush the WAL. It's generally not
    2894             :              * safe to call WaitXLogInsertionsToFinish while holding
    2895             :              * WALWriteLock, because an in-progress insertion might need to
    2896             :              * also grab WALWriteLock to make progress. But we know that all
    2897             :              * the insertions up to insertpos have already finished, because
    2898             :              * that's what the earlier WaitXLogInsertionsToFinish() returned.
    2899             :              * We're only calling it again to allow insertpos to be moved
    2900             :              * further forward, not to actually wait for anyone.
    2901             :              */
    2902           0 :             insertpos = WaitXLogInsertionsToFinish(insertpos);
    2903             :         }
    2904             : 
    2905             :         /* try to write/flush later additions to XLOG as well */
    2906      266058 :         WriteRqst.Write = insertpos;
    2907      266058 :         WriteRqst.Flush = insertpos;
    2908             : 
    2909      266058 :         XLogWrite(WriteRqst, insertTLI, false);
    2910             : 
    2911      266058 :         LWLockRelease(WALWriteLock);
    2912             :         /* done */
    2913      266058 :         break;
    2914             :     }
    2915             : 
    2916      292008 :     END_CRIT_SECTION();
    2917             : 
    2918             :     /* wake up walsenders now that we've released heavily contended locks */
    2919      292008 :     WalSndWakeupProcessRequests(true, !RecoveryInProgress());
    2920             : 
    2921             :     /*
    2922             :      * If we flushed an LSN that someone was waiting for, notify the waiters.
    2923             :      */
    2924      584016 :     if (waitLSNState &&
    2925      292008 :         (LogwrtResult.Flush >=
    2926      292008 :          pg_atomic_read_u64(&waitLSNState->minWaitedLSN[WAIT_LSN_TYPE_PRIMARY_FLUSH])))
    2927           0 :         WaitLSNWakeup(WAIT_LSN_TYPE_PRIMARY_FLUSH, LogwrtResult.Flush);
    2928             : 
    2929             :     /*
    2930             :      * If we still haven't flushed to the request point then we have a
    2931             :      * problem; most likely, the requested flush point is past end of XLOG.
    2932             :      * This has been seen to occur when a disk page has a corrupted LSN.
    2933             :      *
    2934             :      * Formerly we treated this as a PANIC condition, but that hurts the
    2935             :      * system's robustness rather than helping it: we do not want to take down
    2936             :      * the whole system due to corruption on one data page.  In particular, if
    2937             :      * the bad page is encountered again during recovery then we would be
    2938             :      * unable to restart the database at all!  (This scenario actually
    2939             :      * happened in the field several times with 7.1 releases.)  As of 8.4, bad
    2940             :      * LSNs encountered during recovery are UpdateMinRecoveryPoint's problem;
    2941             :      * the only time we can reach here during recovery is while flushing the
    2942             :      * end-of-recovery checkpoint record, and we don't expect that to have a
    2943             :      * bad LSN.
    2944             :      *
    2945             :      * Note that for calls from xact.c, the ERROR will be promoted to PANIC
    2946             :      * since xact.c calls this routine inside a critical section.  However,
    2947             :      * calls from bufmgr.c are not within critical sections and so we will not
    2948             :      * force a restart for a bad LSN on a data page.
    2949             :      */
    2950      292008 :     if (LogwrtResult.Flush < record)
    2951           0 :         elog(ERROR,
    2952             :              "xlog flush request %X/%08X is not satisfied --- flushed only to %X/%08X",
    2953             :              LSN_FORMAT_ARGS(record),
    2954             :              LSN_FORMAT_ARGS(LogwrtResult.Flush));
    2955             : 
    2956             :     /*
    2957             :      * Cross-check XLogNeedsFlush().  Some of the checks of XLogFlush() and
    2958             :      * XLogNeedsFlush() are duplicated, and this assertion ensures that these
    2959             :      * remain consistent.
    2960             :      */
    2961             :     Assert(!XLogNeedsFlush(record));
    2962             : }
    2963             : 
    2964             : /*
    2965             :  * Write & flush xlog, but without specifying exactly where to.
    2966             :  *
    2967             :  * We normally write only completed blocks; but if there is nothing to do on
    2968             :  * that basis, we check for unwritten async commits in the current incomplete
    2969             :  * block, and write through the latest one of those.  Thus, if async commits
    2970             :  * are not being used, we will write complete blocks only.
    2971             :  *
    2972             :  * If, based on the above, there's anything to write we do so immediately. But
    2973             :  * to avoid calling fsync, fdatasync et. al. at a rate that'd impact
    2974             :  * concurrent IO, we only flush WAL every wal_writer_delay ms, or if there's
    2975             :  * more than wal_writer_flush_after unflushed blocks.
    2976             :  *
    2977             :  * We can guarantee that async commits reach disk after at most three
    2978             :  * wal_writer_delay cycles. (When flushing complete blocks, we allow XLogWrite
    2979             :  * to write "flexibly", meaning it can stop at the end of the buffer ring;
    2980             :  * this makes a difference only with very high load or long wal_writer_delay,
    2981             :  * but imposes one extra cycle for the worst case for async commits.)
    2982             :  *
    2983             :  * This routine is invoked periodically by the background walwriter process.
    2984             :  *
    2985             :  * Returns true if there was any work to do, even if we skipped flushing due
    2986             :  * to wal_writer_delay/wal_writer_flush_after.
    2987             :  */
    2988             : bool
    2989       29602 : XLogBackgroundFlush(void)
    2990             : {
    2991             :     XLogwrtRqst WriteRqst;
    2992       29602 :     bool        flexible = true;
    2993             :     static TimestampTz lastflush;
    2994             :     TimestampTz now;
    2995             :     int         flushblocks;
    2996             :     TimeLineID  insertTLI;
    2997             : 
    2998             :     /* XLOG doesn't need flushing during recovery */
    2999       29602 :     if (RecoveryInProgress())
    3000          12 :         return false;
    3001             : 
    3002             :     /*
    3003             :      * Since we're not in recovery, InsertTimeLineID is set and can't change,
    3004             :      * so we can read it without a lock.
    3005             :      */
    3006       29590 :     insertTLI = XLogCtl->InsertTimeLineID;
    3007             : 
    3008             :     /* read updated LogwrtRqst */
    3009       29590 :     SpinLockAcquire(&XLogCtl->info_lck);
    3010       29590 :     WriteRqst = XLogCtl->LogwrtRqst;
    3011       29590 :     SpinLockRelease(&XLogCtl->info_lck);
    3012             : 
    3013             :     /* back off to last completed page boundary */
    3014       29590 :     WriteRqst.Write -= WriteRqst.Write % XLOG_BLCKSZ;
    3015             : 
    3016             :     /* if we have already flushed that far, consider async commit records */
    3017       29590 :     RefreshXLogWriteResult(LogwrtResult);
    3018       29590 :     if (WriteRqst.Write <= LogwrtResult.Flush)
    3019             :     {
    3020       21840 :         SpinLockAcquire(&XLogCtl->info_lck);
    3021       21840 :         WriteRqst.Write = XLogCtl->asyncXactLSN;
    3022       21840 :         SpinLockRelease(&XLogCtl->info_lck);
    3023       21840 :         flexible = false;       /* ensure it all gets written */
    3024             :     }
    3025             : 
    3026             :     /*
    3027             :      * If already known flushed, we're done. Just need to check if we are
    3028             :      * holding an open file handle to a logfile that's no longer in use,
    3029             :      * preventing the file from being deleted.
    3030             :      */
    3031       29590 :     if (WriteRqst.Write <= LogwrtResult.Flush)
    3032             :     {
    3033       20272 :         if (openLogFile >= 0)
    3034             :         {
    3035       12658 :             if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo,
    3036             :                                  wal_segment_size))
    3037             :             {
    3038         276 :                 XLogFileClose();
    3039             :             }
    3040             :         }
    3041       20272 :         return false;
    3042             :     }
    3043             : 
    3044             :     /*
    3045             :      * Determine how far to flush WAL, based on the wal_writer_delay and
    3046             :      * wal_writer_flush_after GUCs.
    3047             :      *
    3048             :      * Note that XLogSetAsyncXactLSN() performs similar calculation based on
    3049             :      * wal_writer_flush_after, to decide when to wake us up.  Make sure the
    3050             :      * logic is the same in both places if you change this.
    3051             :      */
    3052        9318 :     now = GetCurrentTimestamp();
    3053        9318 :     flushblocks =
    3054        9318 :         WriteRqst.Write / XLOG_BLCKSZ - LogwrtResult.Flush / XLOG_BLCKSZ;
    3055             : 
    3056        9318 :     if (WalWriterFlushAfter == 0 || lastflush == 0)
    3057             :     {
    3058             :         /* first call, or block based limits disabled */
    3059         534 :         WriteRqst.Flush = WriteRqst.Write;
    3060         534 :         lastflush = now;
    3061             :     }
    3062        8784 :     else if (TimestampDifferenceExceeds(lastflush, now, WalWriterDelay))
    3063             :     {
    3064             :         /*
    3065             :          * Flush the writes at least every WalWriterDelay ms. This is
    3066             :          * important to bound the amount of time it takes for an asynchronous
    3067             :          * commit to hit disk.
    3068             :          */
    3069        8476 :         WriteRqst.Flush = WriteRqst.Write;
    3070        8476 :         lastflush = now;
    3071             :     }
    3072         308 :     else if (flushblocks >= WalWriterFlushAfter)
    3073             :     {
    3074             :         /* exceeded wal_writer_flush_after blocks, flush */
    3075         282 :         WriteRqst.Flush = WriteRqst.Write;
    3076         282 :         lastflush = now;
    3077             :     }
    3078             :     else
    3079             :     {
    3080             :         /* no flushing, this time round */
    3081          26 :         WriteRqst.Flush = 0;
    3082             :     }
    3083             : 
    3084             : #ifdef WAL_DEBUG
    3085             :     if (XLOG_DEBUG)
    3086             :         elog(LOG, "xlog bg flush request write %X/%08X; flush: %X/%08X, current is write %X/%08X; flush %X/%08X",
    3087             :              LSN_FORMAT_ARGS(WriteRqst.Write),
    3088             :              LSN_FORMAT_ARGS(WriteRqst.Flush),
    3089             :              LSN_FORMAT_ARGS(LogwrtResult.Write),
    3090             :              LSN_FORMAT_ARGS(LogwrtResult.Flush));
    3091             : #endif
    3092             : 
    3093        9318 :     START_CRIT_SECTION();
    3094             : 
    3095             :     /* now wait for any in-progress insertions to finish and get write lock */
    3096        9318 :     WaitXLogInsertionsToFinish(WriteRqst.Write);
    3097        9318 :     LWLockAcquire(WALWriteLock, LW_EXCLUSIVE);
    3098        9318 :     RefreshXLogWriteResult(LogwrtResult);
    3099        9318 :     if (WriteRqst.Write > LogwrtResult.Write ||
    3100         444 :         WriteRqst.Flush > LogwrtResult.Flush)
    3101             :     {
    3102        9004 :         XLogWrite(WriteRqst, insertTLI, flexible);
    3103             :     }
    3104        9318 :     LWLockRelease(WALWriteLock);
    3105             : 
    3106        9318 :     END_CRIT_SECTION();
    3107             : 
    3108             :     /* wake up walsenders now that we've released heavily contended locks */
    3109        9318 :     WalSndWakeupProcessRequests(true, !RecoveryInProgress());
    3110             : 
    3111             :     /*
    3112             :      * If we flushed an LSN that someone was waiting for, notify the waiters.
    3113             :      */
    3114       18636 :     if (waitLSNState &&
    3115        9318 :         (LogwrtResult.Flush >=
    3116        9318 :          pg_atomic_read_u64(&waitLSNState->minWaitedLSN[WAIT_LSN_TYPE_PRIMARY_FLUSH])))
    3117           0 :         WaitLSNWakeup(WAIT_LSN_TYPE_PRIMARY_FLUSH, LogwrtResult.Flush);
    3118             : 
    3119             :     /*
    3120             :      * Great, done. To take some work off the critical path, try to initialize
    3121             :      * as many of the no-longer-needed WAL buffers for future use as we can.
    3122             :      */
    3123        9318 :     AdvanceXLInsertBuffer(InvalidXLogRecPtr, insertTLI, true);
    3124             : 
    3125             :     /*
    3126             :      * If we determined that we need to write data, but somebody else
    3127             :      * wrote/flushed already, it should be considered as being active, to
    3128             :      * avoid hibernating too early.
    3129             :      */
    3130        9318 :     return true;
    3131             : }
    3132             : 
    3133             : /*
    3134             :  * Test whether XLOG data has been flushed up to (at least) the given
    3135             :  * position, or whether the minimum recovery point has been updated past
    3136             :  * the given position.
    3137             :  *
    3138             :  * Returns true if a flush is still needed, or if the minimum recovery point
    3139             :  * must be updated.
    3140             :  *
    3141             :  * It is possible that someone else is already in the process of flushing
    3142             :  * that far, or has updated the minimum recovery point up to the given
    3143             :  * position.
    3144             :  */
    3145             : bool
    3146    17735378 : XLogNeedsFlush(XLogRecPtr record)
    3147             : {
    3148             :     /*
    3149             :      * During recovery, we don't flush WAL but update minRecoveryPoint
    3150             :      * instead. So "needs flush" is taken to mean whether minRecoveryPoint
    3151             :      * would need to be updated.
    3152             :      *
    3153             :      * Using XLogInsertAllowed() rather than RecoveryInProgress() matters for
    3154             :      * the case of an end-of-recovery checkpoint, where WAL data is flushed.
    3155             :      * This check should be consistent with the one in XLogFlush().
    3156             :      */
    3157    17735378 :     if (!XLogInsertAllowed())
    3158             :     {
    3159             :         /* Quick exit if already known to be updated or cannot be updated */
    3160     1268958 :         if (!updateMinRecoveryPoint || record <= LocalMinRecoveryPoint)
    3161     1246204 :             return false;
    3162             : 
    3163             :         /*
    3164             :          * An invalid minRecoveryPoint means that we need to recover all the
    3165             :          * WAL, i.e., we're doing crash recovery.  We never modify the control
    3166             :          * file's value in that case, so we can short-circuit future checks
    3167             :          * here too.  This triggers a quick exit path for the startup process,
    3168             :          * which cannot update its local copy of minRecoveryPoint as long as
    3169             :          * it has not replayed all WAL available when doing crash recovery.
    3170             :          */
    3171       22754 :         if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
    3172             :         {
    3173           0 :             updateMinRecoveryPoint = false;
    3174           0 :             return false;
    3175             :         }
    3176             : 
    3177             :         /*
    3178             :          * Update local copy of minRecoveryPoint. But if the lock is busy,
    3179             :          * just return a conservative guess.
    3180             :          */
    3181       22754 :         if (!LWLockConditionalAcquire(ControlFileLock, LW_SHARED))
    3182           0 :             return true;
    3183       22754 :         LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
    3184       22754 :         LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
    3185       22754 :         LWLockRelease(ControlFileLock);
    3186             : 
    3187             :         /*
    3188             :          * Check minRecoveryPoint for any other process than the startup
    3189             :          * process doing crash recovery, which should not update the control
    3190             :          * file value if crash recovery is still running.
    3191             :          */
    3192       22754 :         if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
    3193           0 :             updateMinRecoveryPoint = false;
    3194             : 
    3195             :         /* check again */
    3196       22754 :         if (record <= LocalMinRecoveryPoint || !updateMinRecoveryPoint)
    3197         150 :             return false;
    3198             :         else
    3199       22604 :             return true;
    3200             :     }
    3201             : 
    3202             :     /* Quick exit if already known flushed */
    3203    16466420 :     if (record <= LogwrtResult.Flush)
    3204    16046744 :         return false;
    3205             : 
    3206             :     /* read LogwrtResult and update local state */
    3207      419676 :     RefreshXLogWriteResult(LogwrtResult);
    3208             : 
    3209             :     /* check again */
    3210      419676 :     if (record <= LogwrtResult.Flush)
    3211        6906 :         return false;
    3212             : 
    3213      412770 :     return true;
    3214             : }
    3215             : 
    3216             : /*
    3217             :  * Try to make a given XLOG file segment exist.
    3218             :  *
    3219             :  * logsegno: identify segment.
    3220             :  *
    3221             :  * *added: on return, true if this call raised the number of extant segments.
    3222             :  *
    3223             :  * path: on return, this char[MAXPGPATH] has the path to the logsegno file.
    3224             :  *
    3225             :  * Returns -1 or FD of opened file.  A -1 here is not an error; a caller
    3226             :  * wanting an open segment should attempt to open "path", which usually will
    3227             :  * succeed.  (This is weird, but it's efficient for the callers.)
    3228             :  */
    3229             : static int
    3230       29634 : XLogFileInitInternal(XLogSegNo logsegno, TimeLineID logtli,
    3231             :                      bool *added, char *path)
    3232             : {
    3233             :     char        tmppath[MAXPGPATH];
    3234             :     XLogSegNo   installed_segno;
    3235             :     XLogSegNo   max_segno;
    3236             :     int         fd;
    3237             :     int         save_errno;
    3238       29634 :     int         open_flags = O_RDWR | O_CREAT | O_EXCL | PG_BINARY;
    3239             :     instr_time  io_start;
    3240             : 
    3241             :     Assert(logtli != 0);
    3242             : 
    3243       29634 :     XLogFilePath(path, logtli, logsegno, wal_segment_size);
    3244             : 
    3245             :     /*
    3246             :      * Try to use existent file (checkpoint maker may have created it already)
    3247             :      */
    3248       29634 :     *added = false;
    3249       29634 :     fd = BasicOpenFile(path, O_RDWR | PG_BINARY | O_CLOEXEC |
    3250       29634 :                        get_sync_bit(wal_sync_method));
    3251       29634 :     if (fd < 0)
    3252             :     {
    3253        2968 :         if (errno != ENOENT)
    3254           0 :             ereport(ERROR,
    3255             :                     (errcode_for_file_access(),
    3256             :                      errmsg("could not open file \"%s\": %m", path)));
    3257             :     }
    3258             :     else
    3259       26666 :         return fd;
    3260             : 
    3261             :     /*
    3262             :      * Initialize an empty (all zeroes) segment.  NOTE: it is possible that
    3263             :      * another process is doing the same thing.  If so, we will end up
    3264             :      * pre-creating an extra log segment.  That seems OK, and better than
    3265             :      * holding the lock throughout this lengthy process.
    3266             :      */
    3267        2968 :     elog(DEBUG2, "creating and filling new WAL file");
    3268             : 
    3269        2968 :     snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
    3270             : 
    3271        2968 :     unlink(tmppath);
    3272             : 
    3273        2968 :     if (io_direct_flags & IO_DIRECT_WAL_INIT)
    3274           0 :         open_flags |= PG_O_DIRECT;
    3275             : 
    3276             :     /* do not use get_sync_bit() here --- want to fsync only at end of fill */
    3277        2968 :     fd = BasicOpenFile(tmppath, open_flags);
    3278        2968 :     if (fd < 0)
    3279           0 :         ereport(ERROR,
    3280             :                 (errcode_for_file_access(),
    3281             :                  errmsg("could not create file \"%s\": %m", tmppath)));
    3282             : 
    3283             :     /* Measure I/O timing when initializing segment */
    3284        2968 :     io_start = pgstat_prepare_io_time(track_wal_io_timing);
    3285             : 
    3286        2968 :     pgstat_report_wait_start(WAIT_EVENT_WAL_INIT_WRITE);
    3287        2968 :     save_errno = 0;
    3288        2968 :     if (wal_init_zero)
    3289             :     {
    3290             :         ssize_t     rc;
    3291             : 
    3292             :         /*
    3293             :          * Zero-fill the file.  With this setting, we do this the hard way to
    3294             :          * ensure that all the file space has really been allocated.  On
    3295             :          * platforms that allow "holes" in files, just seeking to the end
    3296             :          * doesn't allocate intermediate space.  This way, we know that we
    3297             :          * have all the space and (after the fsync below) that all the
    3298             :          * indirect blocks are down on disk.  Therefore, fdatasync(2) or
    3299             :          * O_DSYNC will be sufficient to sync future writes to the log file.
    3300             :          */
    3301        2968 :         rc = pg_pwrite_zeros(fd, wal_segment_size, 0);
    3302             : 
    3303        2968 :         if (rc < 0)
    3304           0 :             save_errno = errno;
    3305             :     }
    3306             :     else
    3307             :     {
    3308             :         /*
    3309             :          * Otherwise, seeking to the end and writing a solitary byte is
    3310             :          * enough.
    3311             :          */
    3312           0 :         errno = 0;
    3313           0 :         if (pg_pwrite(fd, "\0", 1, wal_segment_size - 1) != 1)
    3314             :         {
    3315             :             /* if write didn't set errno, assume no disk space */
    3316           0 :             save_errno = errno ? errno : ENOSPC;
    3317             :         }
    3318             :     }
    3319        2968 :     pgstat_report_wait_end();
    3320             : 
    3321             :     /*
    3322             :      * A full segment worth of data is written when using wal_init_zero. One
    3323             :      * byte is written when not using it.
    3324             :      */
    3325        2968 :     pgstat_count_io_op_time(IOOBJECT_WAL, IOCONTEXT_INIT, IOOP_WRITE,
    3326             :                             io_start, 1,
    3327        2968 :                             wal_init_zero ? wal_segment_size : 1);
    3328             : 
    3329        2968 :     if (save_errno)
    3330             :     {
    3331             :         /*
    3332             :          * If we fail to make the file, delete it to release disk space
    3333             :          */
    3334           0 :         unlink(tmppath);
    3335             : 
    3336           0 :         close(fd);
    3337             : 
    3338           0 :         errno = save_errno;
    3339             : 
    3340           0 :         ereport(ERROR,
    3341             :                 (errcode_for_file_access(),
    3342             :                  errmsg("could not write to file \"%s\": %m", tmppath)));
    3343             :     }
    3344             : 
    3345             :     /* Measure I/O timing when flushing segment */
    3346        2968 :     io_start = pgstat_prepare_io_time(track_wal_io_timing);
    3347             : 
    3348        2968 :     pgstat_report_wait_start(WAIT_EVENT_WAL_INIT_SYNC);
    3349        2968 :     if (pg_fsync(fd) != 0)
    3350             :     {
    3351           0 :         save_errno = errno;
    3352           0 :         close(fd);
    3353           0 :         errno = save_errno;
    3354           0 :         ereport(ERROR,
    3355             :                 (errcode_for_file_access(),
    3356             :                  errmsg("could not fsync file \"%s\": %m", tmppath)));
    3357             :     }
    3358        2968 :     pgstat_report_wait_end();
    3359             : 
    3360        2968 :     pgstat_count_io_op_time(IOOBJECT_WAL, IOCONTEXT_INIT,
    3361             :                             IOOP_FSYNC, io_start, 1, 0);
    3362             : 
    3363        2968 :     if (close(fd) != 0)
    3364           0 :         ereport(ERROR,
    3365             :                 (errcode_for_file_access(),
    3366             :                  errmsg("could not close file \"%s\": %m", tmppath)));
    3367             : 
    3368             :     /*
    3369             :      * Now move the segment into place with its final name.  Cope with
    3370             :      * possibility that someone else has created the file while we were
    3371             :      * filling ours: if so, use ours to pre-create a future log segment.
    3372             :      */
    3373        2968 :     installed_segno = logsegno;
    3374             : 
    3375             :     /*
    3376             :      * XXX: What should we use as max_segno? We used to use XLOGfileslop when
    3377             :      * that was a constant, but that was always a bit dubious: normally, at a
    3378             :      * checkpoint, XLOGfileslop was the offset from the checkpoint record, but
    3379             :      * here, it was the offset from the insert location. We can't do the
    3380             :      * normal XLOGfileslop calculation here because we don't have access to
    3381             :      * the prior checkpoint's redo location. So somewhat arbitrarily, just use
    3382             :      * CheckPointSegments.
    3383             :      */
    3384        2968 :     max_segno = logsegno + CheckPointSegments;
    3385        2968 :     if (InstallXLogFileSegment(&installed_segno, tmppath, true, max_segno,
    3386             :                                logtli))
    3387             :     {
    3388        2968 :         *added = true;
    3389        2968 :         elog(DEBUG2, "done creating and filling new WAL file");
    3390             :     }
    3391             :     else
    3392             :     {
    3393             :         /*
    3394             :          * No need for any more future segments, or InstallXLogFileSegment()
    3395             :          * failed to rename the file into place. If the rename failed, a
    3396             :          * caller opening the file may fail.
    3397             :          */
    3398           0 :         unlink(tmppath);
    3399           0 :         elog(DEBUG2, "abandoned new WAL file");
    3400             :     }
    3401             : 
    3402        2968 :     return -1;
    3403             : }
    3404             : 
    3405             : /*
    3406             :  * Create a new XLOG file segment, or open a pre-existing one.
    3407             :  *
    3408             :  * logsegno: identify segment to be created/opened.
    3409             :  *
    3410             :  * Returns FD of opened file.
    3411             :  *
    3412             :  * Note: errors here are ERROR not PANIC because we might or might not be
    3413             :  * inside a critical section (eg, during checkpoint there is no reason to
    3414             :  * take down the system on failure).  They will promote to PANIC if we are
    3415             :  * in a critical section.
    3416             :  */
    3417             : int
    3418       29110 : XLogFileInit(XLogSegNo logsegno, TimeLineID logtli)
    3419             : {
    3420             :     bool        ignore_added;
    3421             :     char        path[MAXPGPATH];
    3422             :     int         fd;
    3423             : 
    3424             :     Assert(logtli != 0);
    3425             : 
    3426       29110 :     fd = XLogFileInitInternal(logsegno, logtli, &ignore_added, path);
    3427       29110 :     if (fd >= 0)
    3428       26430 :         return fd;
    3429             : 
    3430             :     /* Now open original target segment (might not be file I just made) */
    3431        2680 :     fd = BasicOpenFile(path, O_RDWR | PG_BINARY | O_CLOEXEC |
    3432        2680 :                        get_sync_bit(wal_sync_method));
    3433        2680 :     if (fd < 0)
    3434           0 :         ereport(ERROR,
    3435             :                 (errcode_for_file_access(),
    3436             :                  errmsg("could not open file \"%s\": %m", path)));
    3437        2680 :     return fd;
    3438             : }
    3439             : 
    3440             : /*
    3441             :  * Create a new XLOG file segment by copying a pre-existing one.
    3442             :  *
    3443             :  * destsegno: identify segment to be created.
    3444             :  *
    3445             :  * srcTLI, srcsegno: identify segment to be copied (could be from
    3446             :  *      a different timeline)
    3447             :  *
    3448             :  * upto: how much of the source file to copy (the rest is filled with
    3449             :  *      zeros)
    3450             :  *
    3451             :  * Currently this is only used during recovery, and so there are no locking
    3452             :  * considerations.  But we should be just as tense as XLogFileInit to avoid
    3453             :  * emplacing a bogus file.
    3454             :  */
    3455             : static void
    3456          90 : XLogFileCopy(TimeLineID destTLI, XLogSegNo destsegno,
    3457             :              TimeLineID srcTLI, XLogSegNo srcsegno,
    3458             :              int upto)
    3459             : {
    3460             :     char        path[MAXPGPATH];
    3461             :     char        tmppath[MAXPGPATH];
    3462             :     PGAlignedXLogBlock buffer;
    3463             :     int         srcfd;
    3464             :     int         fd;
    3465             :     int         nbytes;
    3466             : 
    3467             :     /*
    3468             :      * Open the source file
    3469             :      */
    3470          90 :     XLogFilePath(path, srcTLI, srcsegno, wal_segment_size);
    3471          90 :     srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
    3472          90 :     if (srcfd < 0)
    3473           0 :         ereport(ERROR,
    3474             :                 (errcode_for_file_access(),
    3475             :                  errmsg("could not open file \"%s\": %m", path)));
    3476             : 
    3477             :     /*
    3478             :      * Copy into a temp file name.
    3479             :      */
    3480          90 :     snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
    3481             : 
    3482          90 :     unlink(tmppath);
    3483             : 
    3484             :     /* do not use get_sync_bit() here --- want to fsync only at end of fill */
    3485          90 :     fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
    3486          90 :     if (fd < 0)
    3487           0 :         ereport(ERROR,
    3488             :                 (errcode_for_file_access(),
    3489             :                  errmsg("could not create file \"%s\": %m", tmppath)));
    3490             : 
    3491             :     /*
    3492             :      * Do the data copying.
    3493             :      */
    3494      184410 :     for (nbytes = 0; nbytes < wal_segment_size; nbytes += sizeof(buffer))
    3495             :     {
    3496             :         int         nread;
    3497             : 
    3498      184320 :         nread = upto - nbytes;
    3499             : 
    3500             :         /*
    3501             :          * The part that is not read from the source file is filled with
    3502             :          * zeros.
    3503             :          */
    3504      184320 :         if (nread < sizeof(buffer))
    3505          90 :             memset(buffer.data, 0, sizeof(buffer));
    3506             : 
    3507      184320 :         if (nread > 0)
    3508             :         {
    3509             :             int         r;
    3510             : 
    3511        5452 :             if (nread > sizeof(buffer))
    3512        5362 :                 nread = sizeof(buffer);
    3513        5452 :             pgstat_report_wait_start(WAIT_EVENT_WAL_COPY_READ);
    3514        5452 :             r = read(srcfd, buffer.data, nread);
    3515        5452 :             if (r != nread)
    3516             :             {
    3517           0 :                 if (r < 0)
    3518           0 :                     ereport(ERROR,
    3519             :                             (errcode_for_file_access(),
    3520             :                              errmsg("could not read file \"%s\": %m",
    3521             :                                     path)));
    3522             :                 else
    3523           0 :                     ereport(ERROR,
    3524             :                             (errcode(ERRCODE_DATA_CORRUPTED),
    3525             :                              errmsg("could not read file \"%s\": read %d of %zu",
    3526             :                                     path, r, (Size) nread)));
    3527             :             }
    3528        5452 :             pgstat_report_wait_end();
    3529             :         }
    3530      184320 :         errno = 0;
    3531      184320 :         pgstat_report_wait_start(WAIT_EVENT_WAL_COPY_WRITE);
    3532      184320 :         if ((int) write(fd, buffer.data, sizeof(buffer)) != (int) sizeof(buffer))
    3533             :         {
    3534           0 :             int         save_errno = errno;
    3535             : 
    3536             :             /*
    3537             :              * If we fail to make the file, delete it to release disk space
    3538             :              */
    3539           0 :             unlink(tmppath);
    3540             :             /* if write didn't set errno, assume problem is no disk space */
    3541           0 :             errno = save_errno ? save_errno : ENOSPC;
    3542             : 
    3543           0 :             ereport(ERROR,
    3544             :                     (errcode_for_file_access(),
    3545             :                      errmsg("could not write to file \"%s\": %m", tmppath)));
    3546             :         }
    3547      184320 :         pgstat_report_wait_end();
    3548             :     }
    3549             : 
    3550          90 :     pgstat_report_wait_start(WAIT_EVENT_WAL_COPY_SYNC);
    3551          90 :     if (pg_fsync(fd) != 0)
    3552           0 :         ereport(data_sync_elevel(ERROR),
    3553             :                 (errcode_for_file_access(),
    3554             :                  errmsg("could not fsync file \"%s\": %m", tmppath)));
    3555          90 :     pgstat_report_wait_end();
    3556             : 
    3557          90 :     if (CloseTransientFile(fd) != 0)
    3558           0 :         ereport(ERROR,
    3559             :                 (errcode_for_file_access(),
    3560             :                  errmsg("could not close file \"%s\": %m", tmppath)));
    3561             : 
    3562          90 :     if (CloseTransientFile(srcfd) != 0)
    3563           0 :         ereport(ERROR,
    3564             :                 (errcode_for_file_access(),
    3565             :                  errmsg("could not close file \"%s\": %m", path)));
    3566             : 
    3567             :     /*
    3568             :      * Now move the segment into place with its final name.
    3569             :      */
    3570          90 :     if (!InstallXLogFileSegment(&destsegno, tmppath, false, 0, destTLI))
    3571           0 :         elog(ERROR, "InstallXLogFileSegment should not have failed");
    3572          90 : }
    3573             : 
    3574             : /*
    3575             :  * Install a new XLOG segment file as a current or future log segment.
    3576             :  *
    3577             :  * This is used both to install a newly-created segment (which has a temp
    3578             :  * filename while it's being created) and to recycle an old segment.
    3579             :  *
    3580             :  * *segno: identify segment to install as (or first possible target).
    3581             :  * When find_free is true, this is modified on return to indicate the
    3582             :  * actual installation location or last segment searched.
    3583             :  *
    3584             :  * tmppath: initial name of file to install.  It will be renamed into place.
    3585             :  *
    3586             :  * find_free: if true, install the new segment at the first empty segno
    3587             :  * number at or after the passed numbers.  If false, install the new segment
    3588             :  * exactly where specified, deleting any existing segment file there.
    3589             :  *
    3590             :  * max_segno: maximum segment number to install the new file as.  Fail if no
    3591             :  * free slot is found between *segno and max_segno. (Ignored when find_free
    3592             :  * is false.)
    3593             :  *
    3594             :  * tli: The timeline on which the new segment should be installed.
    3595             :  *
    3596             :  * Returns true if the file was installed successfully.  false indicates that
    3597             :  * max_segno limit was exceeded, the startup process has disabled this
    3598             :  * function for now, or an error occurred while renaming the file into place.
    3599             :  */
    3600             : static bool
    3601        5814 : InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
    3602             :                        bool find_free, XLogSegNo max_segno, TimeLineID tli)
    3603             : {
    3604             :     char        path[MAXPGPATH];
    3605             :     struct stat stat_buf;
    3606             : 
    3607             :     Assert(tli != 0);
    3608             : 
    3609        5814 :     XLogFilePath(path, tli, *segno, wal_segment_size);
    3610             : 
    3611        5814 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    3612        5814 :     if (!XLogCtl->InstallXLogFileSegmentActive)
    3613             :     {
    3614           0 :         LWLockRelease(ControlFileLock);
    3615           0 :         return false;
    3616             :     }
    3617             : 
    3618        5814 :     if (!find_free)
    3619             :     {
    3620             :         /* Force installation: get rid of any pre-existing segment file */
    3621          90 :         durable_unlink(path, DEBUG1);
    3622             :     }
    3623             :     else
    3624             :     {
    3625             :         /* Find a free slot to put it in */
    3626        8806 :         while (stat(path, &stat_buf) == 0)
    3627             :         {
    3628        3128 :             if ((*segno) >= max_segno)
    3629             :             {
    3630             :                 /* Failed to find a free slot within specified range */
    3631          46 :                 LWLockRelease(ControlFileLock);
    3632          46 :                 return false;
    3633             :             }
    3634        3082 :             (*segno)++;
    3635        3082 :             XLogFilePath(path, tli, *segno, wal_segment_size);
    3636             :         }
    3637             :     }
    3638             : 
    3639             :     Assert(access(path, F_OK) != 0 && errno == ENOENT);
    3640        5768 :     if (durable_rename(tmppath, path, LOG) != 0)
    3641             :     {
    3642           0 :         LWLockRelease(ControlFileLock);
    3643             :         /* durable_rename already emitted log message */
    3644           0 :         return false;
    3645             :     }
    3646             : 
    3647        5768 :     LWLockRelease(ControlFileLock);
    3648             : 
    3649        5768 :     return true;
    3650             : }
    3651             : 
    3652             : /*
    3653             :  * Open a pre-existing logfile segment for writing.
    3654             :  */
    3655             : int
    3656         146 : XLogFileOpen(XLogSegNo segno, TimeLineID tli)
    3657             : {
    3658             :     char        path[MAXPGPATH];
    3659             :     int         fd;
    3660             : 
    3661         146 :     XLogFilePath(path, tli, segno, wal_segment_size);
    3662             : 
    3663         146 :     fd = BasicOpenFile(path, O_RDWR | PG_BINARY | O_CLOEXEC |
    3664         146 :                        get_sync_bit(wal_sync_method));
    3665         146 :     if (fd < 0)
    3666           0 :         ereport(PANIC,
    3667             :                 (errcode_for_file_access(),
    3668             :                  errmsg("could not open file \"%s\": %m", path)));
    3669             : 
    3670         146 :     return fd;
    3671             : }
    3672             : 
    3673             : /*
    3674             :  * Close the current logfile segment for writing.
    3675             :  */
    3676             : static void
    3677       12592 : XLogFileClose(void)
    3678             : {
    3679             :     Assert(openLogFile >= 0);
    3680             : 
    3681             :     /*
    3682             :      * WAL segment files will not be re-read in normal operation, so we advise
    3683             :      * the OS to release any cached pages.  But do not do so if WAL archiving
    3684             :      * or streaming is active, because archiver and walsender process could
    3685             :      * use the cache to read the WAL segment.
    3686             :      */
    3687             : #if defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
    3688       12592 :     if (!XLogIsNeeded() && (io_direct_flags & IO_DIRECT_WAL) == 0)
    3689         224 :         (void) posix_fadvise(openLogFile, 0, 0, POSIX_FADV_DONTNEED);
    3690             : #endif
    3691             : 
    3692       12592 :     if (close(openLogFile) != 0)
    3693             :     {
    3694             :         char        xlogfname[MAXFNAMELEN];
    3695           0 :         int         save_errno = errno;
    3696             : 
    3697           0 :         XLogFileName(xlogfname, openLogTLI, openLogSegNo, wal_segment_size);
    3698           0 :         errno = save_errno;
    3699           0 :         ereport(PANIC,
    3700             :                 (errcode_for_file_access(),
    3701             :                  errmsg("could not close file \"%s\": %m", xlogfname)));
    3702             :     }
    3703             : 
    3704       12592 :     openLogFile = -1;
    3705       12592 :     ReleaseExternalFD();
    3706       12592 : }
    3707             : 
    3708             : /*
    3709             :  * Preallocate log files beyond the specified log endpoint.
    3710             :  *
    3711             :  * XXX this is currently extremely conservative, since it forces only one
    3712             :  * future log segment to exist, and even that only if we are 75% done with
    3713             :  * the current one.  This is only appropriate for very low-WAL-volume systems.
    3714             :  * High-volume systems will be OK once they've built up a sufficient set of
    3715             :  * recycled log segments, but the startup transient is likely to include
    3716             :  * a lot of segment creations by foreground processes, which is not so good.
    3717             :  *
    3718             :  * XLogFileInitInternal() can ereport(ERROR).  All known causes indicate big
    3719             :  * trouble; for example, a full filesystem is one cause.  The checkpoint WAL
    3720             :  * and/or ControlFile updates already completed.  If a RequestCheckpoint()
    3721             :  * initiated the present checkpoint and an ERROR ends this function, the
    3722             :  * command that called RequestCheckpoint() fails.  That's not ideal, but it's
    3723             :  * not worth contorting more functions to use caller-specified elevel values.
    3724             :  * (With or without RequestCheckpoint(), an ERROR forestalls some inessential
    3725             :  * reporting and resource reclamation.)
    3726             :  */
    3727             : static void
    3728        4100 : PreallocXlogFiles(XLogRecPtr endptr, TimeLineID tli)
    3729             : {
    3730             :     XLogSegNo   _logSegNo;
    3731             :     int         lf;
    3732             :     bool        added;
    3733             :     char        path[MAXPGPATH];
    3734             :     uint64      offset;
    3735             : 
    3736        4100 :     if (!XLogCtl->InstallXLogFileSegmentActive)
    3737          20 :         return;                 /* unlocked check says no */
    3738             : 
    3739        4080 :     XLByteToPrevSeg(endptr, _logSegNo, wal_segment_size);
    3740        4080 :     offset = XLogSegmentOffset(endptr - 1, wal_segment_size);
    3741        4080 :     if (offset >= (uint32) (0.75 * wal_segment_size))
    3742             :     {
    3743         524 :         _logSegNo++;
    3744         524 :         lf = XLogFileInitInternal(_logSegNo, tli, &added, path);
    3745         524 :         if (lf >= 0)
    3746         236 :             close(lf);
    3747         524 :         if (added)
    3748         288 :             CheckpointStats.ckpt_segs_added++;
    3749             :     }
    3750             : }
    3751             : 
    3752             : /*
    3753             :  * Throws an error if the given log segment has already been removed or
    3754             :  * recycled. The caller should only pass a segment that it knows to have
    3755             :  * existed while the server has been running, as this function always
    3756             :  * succeeds if no WAL segments have been removed since startup.
    3757             :  * 'tli' is only used in the error message.
    3758             :  *
    3759             :  * Note: this function guarantees to keep errno unchanged on return.
    3760             :  * This supports callers that use this to possibly deliver a better
    3761             :  * error message about a missing file, while still being able to throw
    3762             :  * a normal file-access error afterwards, if this does return.
    3763             :  */
    3764             : void
    3765      229990 : CheckXLogRemoved(XLogSegNo segno, TimeLineID tli)
    3766             : {
    3767      229990 :     int         save_errno = errno;
    3768             :     XLogSegNo   lastRemovedSegNo;
    3769             : 
    3770      229990 :     SpinLockAcquire(&XLogCtl->info_lck);
    3771      229990 :     lastRemovedSegNo = XLogCtl->lastRemovedSegNo;
    3772      229990 :     SpinLockRelease(&XLogCtl->info_lck);
    3773             : 
    3774      229990 :     if (segno <= lastRemovedSegNo)
    3775             :     {
    3776             :         char        filename[MAXFNAMELEN];
    3777             : 
    3778           0 :         XLogFileName(filename, tli, segno, wal_segment_size);
    3779           0 :         errno = save_errno;
    3780           0 :         ereport(ERROR,
    3781             :                 (errcode_for_file_access(),
    3782             :                  errmsg("requested WAL segment %s has already been removed",
    3783             :                         filename)));
    3784             :     }
    3785      229990 :     errno = save_errno;
    3786      229990 : }
    3787             : 
    3788             : /*
    3789             :  * Return the last WAL segment removed, or 0 if no segment has been removed
    3790             :  * since startup.
    3791             :  *
    3792             :  * NB: the result can be out of date arbitrarily fast, the caller has to deal
    3793             :  * with that.
    3794             :  */
    3795             : XLogSegNo
    3796        2260 : XLogGetLastRemovedSegno(void)
    3797             : {
    3798             :     XLogSegNo   lastRemovedSegNo;
    3799             : 
    3800        2260 :     SpinLockAcquire(&XLogCtl->info_lck);
    3801        2260 :     lastRemovedSegNo = XLogCtl->lastRemovedSegNo;
    3802        2260 :     SpinLockRelease(&XLogCtl->info_lck);
    3803             : 
    3804        2260 :     return lastRemovedSegNo;
    3805             : }
    3806             : 
    3807             : /*
    3808             :  * Return the oldest WAL segment on the given TLI that still exists in
    3809             :  * XLOGDIR, or 0 if none.
    3810             :  */
    3811             : XLogSegNo
    3812          12 : XLogGetOldestSegno(TimeLineID tli)
    3813             : {
    3814             :     DIR        *xldir;
    3815             :     struct dirent *xlde;
    3816          12 :     XLogSegNo   oldest_segno = 0;
    3817             : 
    3818          12 :     xldir = AllocateDir(XLOGDIR);
    3819          82 :     while ((xlde = ReadDir(xldir, XLOGDIR)) != NULL)
    3820             :     {
    3821             :         TimeLineID  file_tli;
    3822             :         XLogSegNo   file_segno;
    3823             : 
    3824             :         /* Ignore files that are not XLOG segments. */
    3825          70 :         if (!IsXLogFileName(xlde->d_name))
    3826          48 :             continue;
    3827             : 
    3828             :         /* Parse filename to get TLI and segno. */
    3829          22 :         XLogFromFileName(xlde->d_name, &file_tli, &file_segno,
    3830             :                          wal_segment_size);
    3831             : 
    3832             :         /* Ignore anything that's not from the TLI of interest. */
    3833          22 :         if (tli != file_tli)
    3834           0 :             continue;
    3835             : 
    3836             :         /* If it's the oldest so far, update oldest_segno. */
    3837          22 :         if (oldest_segno == 0 || file_segno < oldest_segno)
    3838          20 :             oldest_segno = file_segno;
    3839             :     }
    3840             : 
    3841          12 :     FreeDir(xldir);
    3842          12 :     return oldest_segno;
    3843             : }
    3844             : 
    3845             : /*
    3846             :  * Update the last removed segno pointer in shared memory, to reflect that the
    3847             :  * given XLOG file has been removed.
    3848             :  */
    3849             : static void
    3850        5232 : UpdateLastRemovedPtr(char *filename)
    3851             : {
    3852             :     uint32      tli;
    3853             :     XLogSegNo   segno;
    3854             : 
    3855        5232 :     XLogFromFileName(filename, &tli, &segno, wal_segment_size);
    3856             : 
    3857        5232 :     SpinLockAcquire(&XLogCtl->info_lck);
    3858        5232 :     if (segno > XLogCtl->lastRemovedSegNo)
    3859        2308 :         XLogCtl->lastRemovedSegNo = segno;
    3860        5232 :     SpinLockRelease(&XLogCtl->info_lck);
    3861        5232 : }
    3862             : 
    3863             : /*
    3864             :  * Remove all temporary log files in pg_wal
    3865             :  *
    3866             :  * This is called at the beginning of recovery after a previous crash,
    3867             :  * at a point where no other processes write fresh WAL data.
    3868             :  */
    3869             : static void
    3870         368 : RemoveTempXlogFiles(void)
    3871             : {
    3872             :     DIR        *xldir;
    3873             :     struct dirent *xlde;
    3874             : 
    3875         368 :     elog(DEBUG2, "removing all temporary WAL segments");
    3876             : 
    3877         368 :     xldir = AllocateDir(XLOGDIR);
    3878        2492 :     while ((xlde = ReadDir(xldir, XLOGDIR)) != NULL)
    3879             :     {
    3880             :         char        path[MAXPGPATH];
    3881             : 
    3882        2124 :         if (strncmp(xlde->d_name, "xlogtemp.", 9) != 0)
    3883        2124 :             continue;
    3884             : 
    3885           0 :         snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlde->d_name);
    3886           0 :         unlink(path);
    3887           0 :         elog(DEBUG2, "removed temporary WAL segment \"%s\"", path);
    3888             :     }
    3889         368 :     FreeDir(xldir);
    3890         368 : }
    3891             : 
    3892             : /*
    3893             :  * Recycle or remove all log files older or equal to passed segno.
    3894             :  *
    3895             :  * endptr is current (or recent) end of xlog, and lastredoptr is the
    3896             :  * redo pointer of the last checkpoint. These are used to determine
    3897             :  * whether we want to recycle rather than delete no-longer-wanted log files.
    3898             :  *
    3899             :  * insertTLI is the current timeline for XLOG insertion. Any recycled
    3900             :  * segments should be reused for this timeline.
    3901             :  */
    3902             : static void
    3903        3550 : RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr,
    3904             :                    TimeLineID insertTLI)
    3905             : {
    3906             :     DIR        *xldir;
    3907             :     struct dirent *xlde;
    3908             :     char        lastoff[MAXFNAMELEN];
    3909             :     XLogSegNo   endlogSegNo;
    3910             :     XLogSegNo   recycleSegNo;
    3911             : 
    3912             :     /* Initialize info about where to try to recycle to */
    3913        3550 :     XLByteToSeg(endptr, endlogSegNo, wal_segment_size);
    3914        3550 :     recycleSegNo = XLOGfileslop(lastredoptr);
    3915             : 
    3916             :     /*
    3917             :      * Construct a filename of the last segment to be kept. The timeline ID
    3918             :      * doesn't matter, we ignore that in the comparison. (During recovery,
    3919             :      * InsertTimeLineID isn't set, so we can't use that.)
    3920             :      */
    3921        3550 :     XLogFileName(lastoff, 0, segno, wal_segment_size);
    3922             : 
    3923        3550 :     elog(DEBUG2, "attempting to remove WAL segments older than log file %s",
    3924             :          lastoff);
    3925             : 
    3926        3550 :     xldir = AllocateDir(XLOGDIR);
    3927             : 
    3928       57428 :     while ((xlde = ReadDir(xldir, XLOGDIR)) != NULL)
    3929             :     {
    3930             :         /* Ignore files that are not XLOG segments */
    3931       53878 :         if (!IsXLogFileName(xlde->d_name) &&
    3932       15318 :             !IsPartialXLogFileName(xlde->d_name))
    3933       15310 :             continue;
    3934             : 
    3935             :         /*
    3936             :          * We ignore the timeline part of the XLOG segment identifiers in
    3937             :          * deciding whether a segment is still needed.  This ensures that we
    3938             :          * won't prematurely remove a segment from a parent timeline. We could
    3939             :          * probably be a little more proactive about removing segments of
    3940             :          * non-parent timelines, but that would be a whole lot more
    3941             :          * complicated.
    3942             :          *
    3943             :          * We use the alphanumeric sorting property of the filenames to decide
    3944             :          * which ones are earlier than the lastoff segment.
    3945             :          */
    3946       38568 :         if (strcmp(xlde->d_name + 8, lastoff + 8) <= 0)
    3947             :         {
    3948       10350 :             if (XLogArchiveCheckDone(xlde->d_name))
    3949             :             {
    3950             :                 /* Update the last removed location in shared memory first */
    3951        5232 :                 UpdateLastRemovedPtr(xlde->d_name);
    3952             : 
    3953        5232 :                 RemoveXlogFile(xlde, recycleSegNo, &endlogSegNo, insertTLI);
    3954             :             }
    3955             :         }
    3956             :     }
    3957             : 
    3958        3550 :     FreeDir(xldir);
    3959        3550 : }
    3960             : 
    3961             : /*
    3962             :  * Recycle or remove WAL files that are not part of the given timeline's
    3963             :  * history.
    3964             :  *
    3965             :  * This is called during recovery, whenever we switch to follow a new
    3966             :  * timeline, and at the end of recovery when we create a new timeline. We
    3967             :  * wouldn't otherwise care about extra WAL files lying in pg_wal, but they
    3968             :  * might be leftover pre-allocated or recycled WAL segments on the old timeline
    3969             :  * that we haven't used yet, and contain garbage. If we just leave them in
    3970             :  * pg_wal, they will eventually be archived, and we can't let that happen.
    3971             :  * Files that belong to our timeline history are valid, because we have
    3972             :  * successfully replayed them, but from others we can't be sure.
    3973             :  *
    3974             :  * 'switchpoint' is the current point in WAL where we switch to new timeline,
    3975             :  * and 'newTLI' is the new timeline we switch to.
    3976             :  */
    3977             : void
    3978         134 : RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
    3979             : {
    3980             :     DIR        *xldir;
    3981             :     struct dirent *xlde;
    3982             :     char        switchseg[MAXFNAMELEN];
    3983             :     XLogSegNo   endLogSegNo;
    3984             :     XLogSegNo   switchLogSegNo;
    3985             :     XLogSegNo   recycleSegNo;
    3986             : 
    3987             :     /*
    3988             :      * Initialize info about where to begin the work.  This will recycle,
    3989             :      * somewhat arbitrarily, 10 future segments.
    3990             :      */
    3991         134 :     XLByteToPrevSeg(switchpoint, switchLogSegNo, wal_segment_size);
    3992         134 :     XLByteToSeg(switchpoint, endLogSegNo, wal_segment_size);
    3993         134 :     recycleSegNo = endLogSegNo + 10;
    3994             : 
    3995             :     /*
    3996             :      * Construct a filename of the last segment to be kept.
    3997             :      */
    3998         134 :     XLogFileName(switchseg, newTLI, switchLogSegNo, wal_segment_size);
    3999             : 
    4000         134 :     elog(DEBUG2, "attempting to remove WAL segments newer than log file %s",
    4001             :          switchseg);
    4002             : 
    4003         134 :     xldir = AllocateDir(XLOGDIR);
    4004             : 
    4005        1276 :     while ((xlde = ReadDir(xldir, XLOGDIR)) != NULL)
    4006             :     {
    4007             :         /* Ignore files that are not XLOG segments */
    4008        1142 :         if (!IsXLogFileName(xlde->d_name))
    4009         706 :             continue;
    4010             : 
    4011             :         /*
    4012             :          * Remove files that are on a timeline older than the new one we're
    4013             :          * switching to, but with a segment number >= the first segment on the
    4014             :          * new timeline.
    4015             :          */
    4016         436 :         if (strncmp(xlde->d_name, switchseg, 8) < 0 &&
    4017         284 :             strcmp(xlde->d_name + 8, switchseg + 8) > 0)
    4018             :         {
    4019             :             /*
    4020             :              * If the file has already been marked as .ready, however, don't
    4021             :              * remove it yet. It should be OK to remove it - files that are
    4022             :              * not part of our timeline history are not required for recovery
    4023             :              * - but seems safer to let them be archived and removed later.
    4024             :              */
    4025          34 :             if (!XLogArchiveIsReady(xlde->d_name))
    4026          34 :                 RemoveXlogFile(xlde, recycleSegNo, &endLogSegNo, newTLI);
    4027             :         }
    4028             :     }
    4029             : 
    4030         134 :     FreeDir(xldir);
    4031         134 : }
    4032             : 
    4033             : /*
    4034             :  * Recycle or remove a log file that's no longer needed.
    4035             :  *
    4036             :  * segment_de is the dirent structure of the segment to recycle or remove.
    4037             :  * recycleSegNo is the segment number to recycle up to.  endlogSegNo is
    4038             :  * the segment number of the current (or recent) end of WAL.
    4039             :  *
    4040             :  * endlogSegNo gets incremented if the segment is recycled so as it is not
    4041             :  * checked again with future callers of this function.
    4042             :  *
    4043             :  * insertTLI is the current timeline for XLOG insertion. Any recycled segments
    4044             :  * should be used for this timeline.
    4045             :  */
    4046             : static void
    4047        5266 : RemoveXlogFile(const struct dirent *segment_de,
    4048             :                XLogSegNo recycleSegNo, XLogSegNo *endlogSegNo,
    4049             :                TimeLineID insertTLI)
    4050             : {
    4051             :     char        path[MAXPGPATH];
    4052             : #ifdef WIN32
    4053             :     char        newpath[MAXPGPATH];
    4054             : #endif
    4055        5266 :     const char *segname = segment_de->d_name;
    4056             : 
    4057        5266 :     snprintf(path, MAXPGPATH, XLOGDIR "/%s", segname);
    4058             : 
    4059             :     /*
    4060             :      * Before deleting the file, see if it can be recycled as a future log
    4061             :      * segment. Only recycle normal files, because we don't want to recycle
    4062             :      * symbolic links pointing to a separate archive directory.
    4063             :      */
    4064        5266 :     if (wal_recycle &&
    4065        5266 :         *endlogSegNo <= recycleSegNo &&
    4066        6168 :         XLogCtl->InstallXLogFileSegmentActive && /* callee rechecks this */
    4067        5512 :         get_dirent_type(path, segment_de, false, DEBUG2) == PGFILETYPE_REG &&
    4068        2756 :         InstallXLogFileSegment(endlogSegNo, path,
    4069             :                                true, recycleSegNo, insertTLI))
    4070             :     {
    4071        2710 :         ereport(DEBUG2,
    4072             :                 (errmsg_internal("recycled write-ahead log file \"%s\"",
    4073             :                                  segname)));
    4074        2710 :         CheckpointStats.ckpt_segs_recycled++;
    4075             :         /* Needn't recheck that slot on future iterations */
    4076        2710 :         (*endlogSegNo)++;
    4077             :     }
    4078             :     else
    4079             :     {
    4080             :         /* No need for any more future segments, or recycling failed ... */
    4081             :         int         rc;
    4082             : 
    4083        2556 :         ereport(DEBUG2,
    4084             :                 (errmsg_internal("removing write-ahead log file \"%s\"",
    4085             :                                  segname)));
    4086             : 
    4087             : #ifdef WIN32
    4088             : 
    4089             :         /*
    4090             :          * On Windows, if another process (e.g another backend) holds the file
    4091             :          * open in FILE_SHARE_DELETE mode, unlink will succeed, but the file
    4092             :          * will still show up in directory listing until the last handle is
    4093             :          * closed. To avoid confusing the lingering deleted file for a live
    4094             :          * WAL file that needs to be archived, rename it before deleting it.
    4095             :          *
    4096             :          * If another process holds the file open without FILE_SHARE_DELETE
    4097             :          * flag, rename will fail. We'll try again at the next checkpoint.
    4098             :          */
    4099             :         snprintf(newpath, MAXPGPATH, "%s.deleted", path);
    4100             :         if (rename(path, newpath) != 0)
    4101             :         {
    4102             :             ereport(LOG,
    4103             :                     (errcode_for_file_access(),
    4104             :                      errmsg("could not rename file \"%s\": %m",
    4105             :                             path)));
    4106             :             return;
    4107             :         }
    4108             :         rc = durable_unlink(newpath, LOG);
    4109             : #else
    4110        2556 :         rc = durable_unlink(path, LOG);
    4111             : #endif
    4112        2556 :         if (rc != 0)
    4113             :         {
    4114             :             /* Message already logged by durable_unlink() */
    4115           0 :             return;
    4116             :         }
    4117        2556 :         CheckpointStats.ckpt_segs_removed++;
    4118             :     }
    4119             : 
    4120        5266 :     XLogArchiveCleanup(segname);
    4121             : }
    4122             : 
    4123             : /*
    4124             :  * Verify whether pg_wal, pg_wal/archive_status, and pg_wal/summaries exist.
    4125             :  * If the latter do not exist, recreate them.
    4126             :  *
    4127             :  * It is not the goal of this function to verify the contents of these
    4128             :  * directories, but to help in cases where someone has performed a cluster
    4129             :  * copy for PITR purposes but omitted pg_wal from the copy.
    4130             :  *
    4131             :  * We could also recreate pg_wal if it doesn't exist, but a deliberate
    4132             :  * policy decision was made not to.  It is fairly common for pg_wal to be
    4133             :  * a symlink, and if that was the DBA's intent then automatically making a
    4134             :  * plain directory would result in degraded performance with no notice.
    4135             :  */
    4136             : static void
    4137        1982 : ValidateXLOGDirectoryStructure(void)
    4138             : {
    4139             :     char        path[MAXPGPATH];
    4140             :     struct stat stat_buf;
    4141             : 
    4142             :     /* Check for pg_wal; if it doesn't exist, error out */
    4143        1982 :     if (stat(XLOGDIR, &stat_buf) != 0 ||
    4144        1982 :         !S_ISDIR(stat_buf.st_mode))
    4145           0 :         ereport(FATAL,
    4146             :                 (errcode_for_file_access(),
    4147             :                  errmsg("required WAL directory \"%s\" does not exist",
    4148             :                         XLOGDIR)));
    4149             : 
    4150             :     /* Check for archive_status */
    4151        1982 :     snprintf(path, MAXPGPATH, XLOGDIR "/archive_status");
    4152        1982 :     if (stat(path, &stat_buf) == 0)
    4153             :     {
    4154             :         /* Check for weird cases where it exists but isn't a directory */
    4155        1980 :         if (!S_ISDIR(stat_buf.st_mode))
    4156           0 :             ereport(FATAL,
    4157             :                     (errcode_for_file_access(),
    4158             :                      errmsg("required WAL directory \"%s\" does not exist",
    4159             :                             path)));
    4160             :     }
    4161             :     else
    4162             :     {
    4163           2 :         ereport(LOG,
    4164             :                 (errmsg("creating missing WAL directory \"%s\"", path)));
    4165           2 :         if (MakePGDirectory(path) < 0)
    4166           0 :             ereport(FATAL,
    4167             :                     (errcode_for_file_access(),
    4168             :                      errmsg("could not create missing directory \"%s\": %m",
    4169             :                             path)));
    4170             :     }
    4171             : 
    4172             :     /* Check for summaries */
    4173        1982 :     snprintf(path, MAXPGPATH, XLOGDIR "/summaries");
    4174        1982 :     if (stat(path, &stat_buf) == 0)
    4175             :     {
    4176             :         /* Check for weird cases where it exists but isn't a directory */
    4177        1980 :         if (!S_ISDIR(stat_buf.st_mode))
    4178           0 :             ereport(FATAL,
    4179             :                     (errmsg("required WAL directory \"%s\" does not exist",
    4180             :                             path)));
    4181             :     }
    4182             :     else
    4183             :     {
    4184           2 :         ereport(LOG,
    4185             :                 (errmsg("creating missing WAL directory \"%s\"", path)));
    4186           2 :         if (MakePGDirectory(path) < 0)
    4187           0 :             ereport(FATAL,
    4188             :                     (errmsg("could not create missing directory \"%s\": %m",
    4189             :                             path)));
    4190             :     }
    4191        1982 : }
    4192             : 
    4193             : /*
    4194             :  * Remove previous backup history files.  This also retries creation of
    4195             :  * .ready files for any backup history files for which XLogArchiveNotify
    4196             :  * failed earlier.
    4197             :  */
    4198             : static void
    4199         302 : CleanupBackupHistory(void)
    4200             : {
    4201             :     DIR        *xldir;
    4202             :     struct dirent *xlde;
    4203             :     char        path[MAXPGPATH + sizeof(XLOGDIR)];
    4204             : 
    4205         302 :     xldir = AllocateDir(XLOGDIR);
    4206             : 
    4207        3038 :     while ((xlde = ReadDir(xldir, XLOGDIR)) != NULL)
    4208             :     {
    4209        2434 :         if (IsBackupHistoryFileName(xlde->d_name))
    4210             :         {
    4211         318 :             if (XLogArchiveCheckDone(xlde->d_name))
    4212             :             {
    4213         252 :                 elog(DEBUG2, "removing WAL backup history file \"%s\"",
    4214             :                      xlde->d_name);
    4215         252 :                 snprintf(path, sizeof(path), XLOGDIR "/%s", xlde->d_name);
    4216         252 :                 unlink(path);
    4217         252 :                 XLogArchiveCleanup(xlde->d_name);
    4218             :             }
    4219             :         }
    4220             :     }
    4221             : 
    4222         302 :     FreeDir(xldir);
    4223         302 : }
    4224             : 
    4225             : /*
    4226             :  * I/O routines for pg_control
    4227             :  *
    4228             :  * *ControlFile is a buffer in shared memory that holds an image of the
    4229             :  * contents of pg_control.  WriteControlFile() initializes pg_control
    4230             :  * given a preloaded buffer, ReadControlFile() loads the buffer from
    4231             :  * the pg_control file (during postmaster or standalone-backend startup),
    4232             :  * and UpdateControlFile() rewrites pg_control after we modify xlog state.
    4233             :  * InitControlFile() fills the buffer with initial values.
    4234             :  *
    4235             :  * For simplicity, WriteControlFile() initializes the fields of pg_control
    4236             :  * that are related to checking backend/database compatibility, and
    4237             :  * ReadControlFile() verifies they are correct.  We could split out the
    4238             :  * I/O and compatibility-check functions, but there seems no need currently.
    4239             :  */
    4240             : 
    4241             : static void
    4242         102 : InitControlFile(uint64 sysidentifier, uint32 data_checksum_version)
    4243             : {
    4244             :     char        mock_auth_nonce[MOCK_AUTH_NONCE_LEN];
    4245             : 
    4246             :     /*
    4247             :      * Generate a random nonce. This is used for authentication requests that
    4248             :      * will fail because the user does not exist. The nonce is used to create
    4249             :      * a genuine-looking password challenge for the non-existent user, in lieu
    4250             :      * of an actual stored password.
    4251             :      */
    4252         102 :     if (!pg_strong_random(mock_auth_nonce, MOCK_AUTH_NONCE_LEN))
    4253           0 :         ereport(PANIC,
    4254             :                 (errcode(ERRCODE_INTERNAL_ERROR),
    4255             :                  errmsg("could not generate secret authorization token")));
    4256             : 
    4257         102 :     memset(ControlFile, 0, sizeof(ControlFileData));
    4258             :     /* Initialize pg_control status fields */
    4259         102 :     ControlFile->system_identifier = sysidentifier;
    4260         102 :     memcpy(ControlFile->mock_authentication_nonce, mock_auth_nonce, MOCK_AUTH_NONCE_LEN);
    4261         102 :     ControlFile->state = DB_SHUTDOWNED;
    4262         102 :     ControlFile->unloggedLSN = FirstNormalUnloggedLSN;
    4263             : 
    4264             :     /* Set important parameter values for use when replaying WAL */
    4265         102 :     ControlFile->MaxConnections = MaxConnections;
    4266         102 :     ControlFile->max_worker_processes = max_worker_processes;
    4267         102 :     ControlFile->max_wal_senders = max_wal_senders;
    4268         102 :     ControlFile->max_prepared_xacts = max_prepared_xacts;
    4269         102 :     ControlFile->max_locks_per_xact = max_locks_per_xact;
    4270         102 :     ControlFile->wal_level = wal_level;
    4271         102 :     ControlFile->wal_log_hints = wal_log_hints;
    4272         102 :     ControlFile->track_commit_timestamp = track_commit_timestamp;
    4273         102 :     ControlFile->data_checksum_version = data_checksum_version;
    4274         102 : }
    4275             : 
    4276             : static void
    4277         102 : WriteControlFile(void)
    4278             : {
    4279             :     int         fd;
    4280             :     char        buffer[PG_CONTROL_FILE_SIZE];   /* need not be aligned */
    4281             : 
    4282             :     /*
    4283             :      * Initialize version and compatibility-check fields
    4284             :      */
    4285         102 :     ControlFile->pg_control_version = PG_CONTROL_VERSION;
    4286         102 :     ControlFile->catalog_version_no = CATALOG_VERSION_NO;
    4287             : 
    4288         102 :     ControlFile->maxAlign = MAXIMUM_ALIGNOF;
    4289         102 :     ControlFile->floatFormat = FLOATFORMAT_VALUE;
    4290             : 
    4291         102 :     ControlFile->blcksz = BLCKSZ;
    4292         102 :     ControlFile->relseg_size = RELSEG_SIZE;
    4293         102 :     ControlFile->slru_pages_per_segment = SLRU_PAGES_PER_SEGMENT;
    4294         102 :     ControlFile->xlog_blcksz = XLOG_BLCKSZ;
    4295         102 :     ControlFile->xlog_seg_size = wal_segment_size;
    4296             : 
    4297         102 :     ControlFile->nameDataLen = NAMEDATALEN;
    4298         102 :     ControlFile->indexMaxKeys = INDEX_MAX_KEYS;
    4299             : 
    4300         102 :     ControlFile->toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
    4301         102 :     ControlFile->loblksize = LOBLKSIZE;
    4302             : 
    4303         102 :     ControlFile->float8ByVal = true; /* vestigial */
    4304             : 
    4305             :     /*
    4306             :      * Initialize the default 'char' signedness.
    4307             :      *
    4308             :      * The signedness of the char type is implementation-defined. For instance
    4309             :      * on x86 architecture CPUs, the char data type is typically treated as
    4310             :      * signed by default, whereas on aarch architecture CPUs, it is typically
    4311             :      * treated as unsigned by default. In v17 or earlier, we accidentally let
    4312             :      * C implementation signedness affect persistent data. This led to
    4313             :      * inconsistent results when comparing char data across different
    4314             :      * platforms.
    4315             :      *
    4316             :      * This flag can be used as a hint to ensure consistent behavior for
    4317             :      * pre-v18 data files that store data sorted by the 'char' type on disk,
    4318             :      * especially in cross-platform replication scenarios.
    4319             :      *
    4320             :      * Newly created database clusters unconditionally set the default char
    4321             :      * signedness to true. pg_upgrade changes this flag for clusters that were
    4322             :      * initialized on signedness=false platforms. As a result,
    4323             :      * signedness=false setting will become rare over time. If we had known
    4324             :      * about this problem during the last development cycle that forced initdb
    4325             :      * (v8.3), we would have made all clusters signed or all clusters
    4326             :      * unsigned. Making pg_upgrade the only source of signedness=false will
    4327             :      * cause the population of database clusters to converge toward that
    4328             :      * retrospective ideal.
    4329             :      */
    4330         102 :     ControlFile->default_char_signedness = true;
    4331             : 
    4332             :     /* Contents are protected with a CRC */
    4333         102 :     INIT_CRC32C(ControlFile->crc);
    4334         102 :     COMP_CRC32C(ControlFile->crc,
    4335             :                 ControlFile,
    4336             :                 offsetof(ControlFileData, crc));
    4337         102 :     FIN_CRC32C(ControlFile->crc);
    4338             : 
    4339             :     /*
    4340             :      * We write out PG_CONTROL_FILE_SIZE bytes into pg_control, zero-padding
    4341             :      * the excess over sizeof(ControlFileData).  This reduces the odds of
    4342             :      * premature-EOF errors when reading pg_control.  We'll still fail when we
    4343             :      * check the contents of the file, but hopefully with a more specific
    4344             :      * error than "couldn't read pg_control".
    4345             :      */
    4346         102 :     memset(buffer, 0, PG_CONTROL_FILE_SIZE);
    4347         102 :     memcpy(buffer, ControlFile, sizeof(ControlFileData));
    4348             : 
    4349         102 :     fd = BasicOpenFile(XLOG_CONTROL_FILE,
    4350             :                        O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
    4351         102 :     if (fd < 0)
    4352           0 :         ereport(PANIC,
    4353             :                 (errcode_for_file_access(),
    4354             :                  errmsg("could not create file \"%s\": %m",
    4355             :                         XLOG_CONTROL_FILE)));
    4356             : 
    4357         102 :     errno = 0;
    4358         102 :     pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE);
    4359         102 :     if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE)
    4360             :     {
    4361             :         /* if write didn't set errno, assume problem is no disk space */
    4362           0 :         if (errno == 0)
    4363           0 :             errno = ENOSPC;
    4364           0 :         ereport(PANIC,
    4365             :                 (errcode_for_file_access(),
    4366             :                  errmsg("could not write to file \"%s\": %m",
    4367             :                         XLOG_CONTROL_FILE)));
    4368             :     }
    4369         102 :     pgstat_report_wait_end();
    4370             : 
    4371         102 :     pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_SYNC);
    4372         102 :     if (pg_fsync(fd) != 0)
    4373           0 :         ereport(PANIC,
    4374             :                 (errcode_for_file_access(),
    4375             :                  errmsg("could not fsync file \"%s\": %m",
    4376             :                         XLOG_CONTROL_FILE)));
    4377         102 :     pgstat_report_wait_end();
    4378             : 
    4379         102 :     if (close(fd) != 0)
    4380           0 :         ereport(PANIC,
    4381             :                 (errcode_for_file_access(),
    4382             :                  errmsg("could not close file \"%s\": %m",
    4383             :                         XLOG_CONTROL_FILE)));
    4384         102 : }
    4385             : 
    4386             : static void
    4387        2084 : ReadControlFile(void)
    4388             : {
    4389             :     pg_crc32c   crc;
    4390             :     int         fd;
    4391             :     char        wal_segsz_str[20];
    4392             :     int         r;
    4393             : 
    4394             :     /*
    4395             :      * Read data...
    4396             :      */
    4397        2084 :     fd = BasicOpenFile(XLOG_CONTROL_FILE,
    4398             :                        O_RDWR | PG_BINARY);
    4399        2084 :     if (fd < 0)
    4400           0 :         ereport(PANIC,
    4401             :                 (errcode_for_file_access(),
    4402             :                  errmsg("could not open file \"%s\": %m",
    4403             :                         XLOG_CONTROL_FILE)));
    4404             : 
    4405        2084 :     pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_READ);
    4406        2084 :     r = read(fd, ControlFile, sizeof(ControlFileData));
    4407        2084 :     if (r != sizeof(ControlFileData))
    4408             :     {
    4409           0 :         if (r < 0)
    4410           0 :             ereport(PANIC,
    4411             :                     (errcode_for_file_access(),
    4412             :                      errmsg("could not read file \"%s\": %m",
    4413             :                             XLOG_CONTROL_FILE)));
    4414             :         else
    4415           0 :             ereport(PANIC,
    4416             :                     (errcode(ERRCODE_DATA_CORRUPTED),
    4417             :                      errmsg("could not read file \"%s\": read %d of %zu",
    4418             :                             XLOG_CONTROL_FILE, r, sizeof(ControlFileData))));
    4419             :     }
    4420        2084 :     pgstat_report_wait_end();
    4421             : 
    4422        2084 :     close(fd);
    4423             : 
    4424             :     /*
    4425             :      * Check for expected pg_control format version.  If this is wrong, the
    4426             :      * CRC check will likely fail because we'll be checking the wrong number
    4427             :      * of bytes.  Complaining about wrong version will probably be more
    4428             :      * enlightening than complaining about wrong CRC.
    4429             :      */
    4430             : 
    4431        2084 :     if (ControlFile->pg_control_version != PG_CONTROL_VERSION && ControlFile->pg_control_version % 65536 == 0 && ControlFile->pg_control_version / 65536 != 0)
    4432           0 :         ereport(FATAL,
    4433             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4434             :                  errmsg("database files are incompatible with server"),
    4435             :                  errdetail("The database cluster was initialized with PG_CONTROL_VERSION %d (0x%08x),"
    4436             :                            " but the server was compiled with PG_CONTROL_VERSION %d (0x%08x).",
    4437             :                            ControlFile->pg_control_version, ControlFile->pg_control_version,
    4438             :                            PG_CONTROL_VERSION, PG_CONTROL_VERSION),
    4439             :                  errhint("This could be a problem of mismatched byte ordering.  It looks like you need to initdb.")));
    4440             : 
    4441        2084 :     if (ControlFile->pg_control_version != PG_CONTROL_VERSION)
    4442           0 :         ereport(FATAL,
    4443             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4444             :                  errmsg("database files are incompatible with server"),
    4445             :                  errdetail("The database cluster was initialized with PG_CONTROL_VERSION %d,"
    4446             :                            " but the server was compiled with PG_CONTROL_VERSION %d.",
    4447             :                            ControlFile->pg_control_version, PG_CONTROL_VERSION),
    4448             :                  errhint("It looks like you need to initdb.")));
    4449             : 
    4450             :     /* Now check the CRC. */
    4451        2084 :     INIT_CRC32C(crc);
    4452        2084 :     COMP_CRC32C(crc,
    4453             :                 ControlFile,
    4454             :                 offsetof(ControlFileData, crc));
    4455        2084 :     FIN_CRC32C(crc);
    4456             : 
    4457        2084 :     if (!EQ_CRC32C(crc, ControlFile->crc))
    4458           0 :         ereport(FATAL,
    4459             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4460             :                  errmsg("incorrect checksum in control file")));
    4461             : 
    4462             :     /*
    4463             :      * Do compatibility checking immediately.  If the database isn't
    4464             :      * compatible with the backend executable, we want to abort before we can
    4465             :      * possibly do any damage.
    4466             :      */
    4467        2084 :     if (ControlFile->catalog_version_no != CATALOG_VERSION_NO)
    4468           0 :         ereport(FATAL,
    4469             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4470             :                  errmsg("database files are incompatible with server"),
    4471             :         /* translator: %s is a variable name and %d is its value */
    4472             :                  errdetail("The database cluster was initialized with %s %d,"
    4473             :                            " but the server was compiled with %s %d.",
    4474             :                            "CATALOG_VERSION_NO", ControlFile->catalog_version_no,
    4475             :                            "CATALOG_VERSION_NO", CATALOG_VERSION_NO),
    4476             :                  errhint("It looks like you need to initdb.")));
    4477        2084 :     if (ControlFile->maxAlign != MAXIMUM_ALIGNOF)
    4478           0 :         ereport(FATAL,
    4479             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4480             :                  errmsg("database files are incompatible with server"),
    4481             :         /* translator: %s is a variable name and %d is its value */
    4482             :                  errdetail("The database cluster was initialized with %s %d,"
    4483             :                            " but the server was compiled with %s %d.",
    4484             :                            "MAXALIGN", ControlFile->maxAlign,
    4485             :                            "MAXALIGN", MAXIMUM_ALIGNOF),
    4486             :                  errhint("It looks like you need to initdb.")));
    4487        2084 :     if (ControlFile->floatFormat != FLOATFORMAT_VALUE)
    4488           0 :         ereport(FATAL,
    4489             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4490             :                  errmsg("database files are incompatible with server"),
    4491             :                  errdetail("The database cluster appears to use a different floating-point number format than the server executable."),
    4492             :                  errhint("It looks like you need to initdb.")));
    4493        2084 :     if (ControlFile->blcksz != BLCKSZ)
    4494           0 :         ereport(FATAL,
    4495             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4496             :                  errmsg("database files are incompatible with server"),
    4497             :         /* translator: %s is a variable name and %d is its value */
    4498             :                  errdetail("The database cluster was initialized with %s %d,"
    4499             :                            " but the server was compiled with %s %d.",
    4500             :                            "BLCKSZ", ControlFile->blcksz,
    4501             :                            "BLCKSZ", BLCKSZ),
    4502             :                  errhint("It looks like you need to recompile or initdb.")));
    4503        2084 :     if (ControlFile->relseg_size != RELSEG_SIZE)
    4504           0 :         ereport(FATAL,
    4505             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4506             :                  errmsg("database files are incompatible with server"),
    4507             :         /* translator: %s is a variable name and %d is its value */
    4508             :                  errdetail("The database cluster was initialized with %s %d,"
    4509             :                            " but the server was compiled with %s %d.",
    4510             :                            "RELSEG_SIZE", ControlFile->relseg_size,
    4511             :                            "RELSEG_SIZE", RELSEG_SIZE),
    4512             :                  errhint("It looks like you need to recompile or initdb.")));
    4513        2084 :     if (ControlFile->slru_pages_per_segment != SLRU_PAGES_PER_SEGMENT)
    4514           0 :         ereport(FATAL,
    4515             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4516             :                  errmsg("database files are incompatible with server"),
    4517             :         /* translator: %s is a variable name and %d is its value */
    4518             :                  errdetail("The database cluster was initialized with %s %d,"
    4519             :                            " but the server was compiled with %s %d.",
    4520             :                            "SLRU_PAGES_PER_SEGMENT", ControlFile->slru_pages_per_segment,
    4521             :                            "SLRU_PAGES_PER_SEGMENT", SLRU_PAGES_PER_SEGMENT),
    4522             :                  errhint("It looks like you need to recompile or initdb.")));
    4523        2084 :     if (ControlFile->xlog_blcksz != XLOG_BLCKSZ)
    4524           0 :         ereport(FATAL,
    4525             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4526             :                  errmsg("database files are incompatible with server"),
    4527             :         /* translator: %s is a variable name and %d is its value */
    4528             :                  errdetail("The database cluster was initialized with %s %d,"
    4529             :                            " but the server was compiled with %s %d.",
    4530             :                            "XLOG_BLCKSZ", ControlFile->xlog_blcksz,
    4531             :                            "XLOG_BLCKSZ", XLOG_BLCKSZ),
    4532             :                  errhint("It looks like you need to recompile or initdb.")));
    4533        2084 :     if (ControlFile->nameDataLen != NAMEDATALEN)
    4534           0 :         ereport(FATAL,
    4535             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4536             :                  errmsg("database files are incompatible with server"),
    4537             :         /* translator: %s is a variable name and %d is its value */
    4538             :                  errdetail("The database cluster was initialized with %s %d,"
    4539             :                            " but the server was compiled with %s %d.",
    4540             :                            "NAMEDATALEN", ControlFile->nameDataLen,
    4541             :                            "NAMEDATALEN", NAMEDATALEN),
    4542             :                  errhint("It looks like you need to recompile or initdb.")));
    4543        2084 :     if (ControlFile->indexMaxKeys != INDEX_MAX_KEYS)
    4544           0 :         ereport(FATAL,
    4545             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4546             :                  errmsg("database files are incompatible with server"),
    4547             :         /* translator: %s is a variable name and %d is its value */
    4548             :                  errdetail("The database cluster was initialized with %s %d,"
    4549             :                            " but the server was compiled with %s %d.",
    4550             :                            "INDEX_MAX_KEYS", ControlFile->indexMaxKeys,
    4551             :                            "INDEX_MAX_KEYS", INDEX_MAX_KEYS),
    4552             :                  errhint("It looks like you need to recompile or initdb.")));
    4553        2084 :     if (ControlFile->toast_max_chunk_size != TOAST_MAX_CHUNK_SIZE)
    4554           0 :         ereport(FATAL,
    4555             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4556             :                  errmsg("database files are incompatible with server"),
    4557             :         /* translator: %s is a variable name and %d is its value */
    4558             :                  errdetail("The database cluster was initialized with %s %d,"
    4559             :                            " but the server was compiled with %s %d.",
    4560             :                            "TOAST_MAX_CHUNK_SIZE", ControlFile->toast_max_chunk_size,
    4561             :                            "TOAST_MAX_CHUNK_SIZE", (int) TOAST_MAX_CHUNK_SIZE),
    4562             :                  errhint("It looks like you need to recompile or initdb.")));
    4563        2084 :     if (ControlFile->loblksize != LOBLKSIZE)
    4564           0 :         ereport(FATAL,
    4565             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4566             :                  errmsg("database files are incompatible with server"),
    4567             :         /* translator: %s is a variable name and %d is its value */
    4568             :                  errdetail("The database cluster was initialized with %s %d,"
    4569             :                            " but the server was compiled with %s %d.",
    4570             :                            "LOBLKSIZE", ControlFile->loblksize,
    4571             :                            "LOBLKSIZE", (int) LOBLKSIZE),
    4572             :                  errhint("It looks like you need to recompile or initdb.")));
    4573             : 
    4574             :     Assert(ControlFile->float8ByVal);    /* vestigial, not worth an error msg */
    4575             : 
    4576        2084 :     wal_segment_size = ControlFile->xlog_seg_size;
    4577             : 
    4578        2084 :     if (!IsValidWalSegSize(wal_segment_size))
    4579           0 :         ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4580             :                         errmsg_plural("invalid WAL segment size in control file (%d byte)",
    4581             :                                       "invalid WAL segment size in control file (%d bytes)",
    4582             :                                       wal_segment_size,
    4583             :                                       wal_segment_size),
    4584             :                         errdetail("The WAL segment size must be a power of two between 1 MB and 1 GB.")));
    4585             : 
    4586        2084 :     snprintf(wal_segsz_str, sizeof(wal_segsz_str), "%d", wal_segment_size);
    4587        2084 :     SetConfigOption("wal_segment_size", wal_segsz_str, PGC_INTERNAL,
    4588             :                     PGC_S_DYNAMIC_DEFAULT);
    4589             : 
    4590             :     /* check and update variables dependent on wal_segment_size */
    4591        2084 :     if (ConvertToXSegs(min_wal_size_mb, wal_segment_size) < 2)
    4592           0 :         ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4593             :         /* translator: both %s are GUC names */
    4594             :                         errmsg("\"%s\" must be at least twice \"%s\"",
    4595             :                                "min_wal_size", "wal_segment_size")));
    4596             : 
    4597        2084 :     if (ConvertToXSegs(max_wal_size_mb, wal_segment_size) < 2)
    4598           0 :         ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4599             :         /* translator: both %s are GUC names */
    4600             :                         errmsg("\"%s\" must be at least twice \"%s\"",
    4601             :                                "max_wal_size", "wal_segment_size")));
    4602             : 
    4603        2084 :     UsableBytesInSegment =
    4604        2084 :         (wal_segment_size / XLOG_BLCKSZ * UsableBytesInPage) -
    4605             :         (SizeOfXLogLongPHD - SizeOfXLogShortPHD);
    4606             : 
    4607        2084 :     CalculateCheckpointSegments();
    4608             : 
    4609             :     /* Make the initdb settings visible as GUC variables, too */
    4610        2084 :     SetConfigOption("data_checksums", DataChecksumsEnabled() ? "yes" : "no",
    4611             :                     PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
    4612        2084 : }
    4613             : 
    4614             : /*
    4615             :  * Utility wrapper to update the control file.  Note that the control
    4616             :  * file gets flushed.
    4617             :  */
    4618             : static void
    4619       18772 : UpdateControlFile(void)
    4620             : {
    4621       18772 :     update_controlfile(DataDir, ControlFile, true);
    4622       18772 : }
    4623             : 
    4624             : /*
    4625             :  * Returns the unique system identifier from control file.
    4626             :  */
    4627             : uint64
    4628        2894 : GetSystemIdentifier(void)
    4629             : {
    4630             :     Assert(ControlFile != NULL);
    4631        2894 :     return ControlFile->system_identifier;
    4632             : }
    4633             : 
    4634             : /*
    4635             :  * Returns the random nonce from control file.
    4636             :  */
    4637             : char *
    4638           2 : GetMockAuthenticationNonce(void)
    4639             : {
    4640             :     Assert(ControlFile != NULL);
    4641           2 :     return ControlFile->mock_authentication_nonce;
    4642             : }
    4643             : 
    4644             : /*
    4645             :  * Are checksums enabled for data pages?
    4646             :  */
    4647             : bool
    4648    19950770 : DataChecksumsEnabled(void)
    4649             : {
    4650             :     Assert(ControlFile != NULL);
    4651    19950770 :     return (ControlFile->data_checksum_version > 0);
    4652             : }
    4653             : 
    4654             : /*
    4655             :  * Return true if the cluster was initialized on a platform where the
    4656             :  * default signedness of char is "signed". This function exists for code
    4657             :  * that deals with pre-v18 data files that store data sorted by the 'char'
    4658             :  * type on disk (e.g., GIN and GiST indexes). See the comments in
    4659             :  * WriteControlFile() for details.
    4660             :  */
    4661             : bool
    4662           6 : GetDefaultCharSignedness(void)
    4663             : {
    4664           6 :     return ControlFile->default_char_signedness;
    4665             : }
    4666             : 
    4667             : /*
    4668             :  * Returns a fake LSN for unlogged relations.
    4669             :  *
    4670             :  * Each call generates an LSN that is greater than any previous value
    4671             :  * returned. The current counter value is saved and restored across clean
    4672             :  * shutdowns, but like unlogged relations, does not survive a crash. This can
    4673             :  * be used in lieu of real LSN values returned by XLogInsert, if you need an
    4674             :  * LSN-like increasing sequence of numbers without writing any WAL.
    4675             :  */
    4676             : XLogRecPtr
    4677          66 : GetFakeLSNForUnloggedRel(void)
    4678             : {
    4679          66 :     return pg_atomic_fetch_add_u64(&XLogCtl->unloggedLSN, 1);
    4680             : }
    4681             : 
    4682             : /*
    4683             :  * Auto-tune the number of XLOG buffers.
    4684             :  *
    4685             :  * The preferred setting for wal_buffers is about 3% of shared_buffers, with
    4686             :  * a maximum of one XLOG segment (there is little reason to think that more
    4687             :  * is helpful, at least so long as we force an fsync when switching log files)
    4688             :  * and a minimum of 8 blocks (which was the default value prior to PostgreSQL
    4689             :  * 9.1, when auto-tuning was added).
    4690             :  *
    4691             :  * This should not be called until NBuffers has received its final value.
    4692             :  */
    4693             : static int
    4694        2268 : XLOGChooseNumBuffers(void)
    4695             : {
    4696             :     int         xbuffers;
    4697             : 
    4698        2268 :     xbuffers = NBuffers / 32;
    4699        2268 :     if (xbuffers > (wal_segment_size / XLOG_BLCKSZ))
    4700          48 :         xbuffers = (wal_segment_size / XLOG_BLCKSZ);
    4701        2268 :     if (xbuffers < 8)
    4702         882 :         xbuffers = 8;
    4703        2268 :     return xbuffers;
    4704             : }
    4705             : 
    4706             : /*
    4707             :  * GUC check_hook for wal_buffers
    4708             :  */
    4709             : bool
    4710        4614 : check_wal_buffers(int *newval, void **extra, GucSource source)
    4711             : {
    4712             :     /*
    4713             :      * -1 indicates a request for auto-tune.
    4714             :      */
    4715        4614 :     if (*newval == -1)
    4716             :     {
    4717             :         /*
    4718             :          * If we haven't yet changed the boot_val default of -1, just let it
    4719             :          * be.  We'll fix it when XLOGShmemSize is called.
    4720             :          */
    4721        2346 :         if (XLOGbuffers == -1)
    4722        2346 :             return true;
    4723             : 
    4724             :         /* Otherwise, substitute the auto-tune value */
    4725           0 :         *newval = XLOGChooseNumBuffers();
    4726             :     }
    4727             : 
    4728             :     /*
    4729             :      * We clamp manually-set values to at least 4 blocks.  Prior to PostgreSQL
    4730             :      * 9.1, a minimum of 4 was enforced by guc.c, but since that is no longer
    4731             :      * the case, we just silently treat such values as a request for the
    4732             :      * minimum.  (We could throw an error instead, but that doesn't seem very
    4733             :      * helpful.)
    4734             :      */
    4735        2268 :     if (*newval < 4)
    4736           0 :         *newval = 4;
    4737             : 
    4738        2268 :     return true;
    4739             : }
    4740             : 
    4741             : /*
    4742             :  * GUC check_hook for wal_consistency_checking
    4743             :  */
    4744             : bool
    4745        4230 : check_wal_consistency_checking(char **newval, void **extra, GucSource source)
    4746             : {
    4747             :     char       *rawstring;
    4748             :     List       *elemlist;
    4749             :     ListCell   *l;
    4750             :     bool        newwalconsistency[RM_MAX_ID + 1];
    4751             : 
    4752             :     /* Initialize the array */
    4753      139590 :     MemSet(newwalconsistency, 0, (RM_MAX_ID + 1) * sizeof(bool));
    4754             : 
    4755             :     /* Need a modifiable copy of string */
    4756        4230 :     rawstring = pstrdup(*newval);
    4757             : 
    4758             :     /* Parse string into list of identifiers */
    4759        4230 :     if (!SplitIdentifierString(rawstring, ',', &elemlist))
    4760             :     {
    4761             :         /* syntax error in list */
    4762           0 :         GUC_check_errdetail("List syntax is invalid.");
    4763           0 :         pfree(rawstring);
    4764           0 :         list_free(elemlist);
    4765           0 :         return false;
    4766             :     }
    4767             : 
    4768        5178 :     foreach(l, elemlist)
    4769             :     {
    4770         948 :         char       *tok = (char *) lfirst(l);
    4771             :         int         rmid;
    4772             : 
    4773             :         /* Check for 'all'. */
    4774         948 :         if (pg_strcasecmp(tok, "all") == 0)
    4775             :         {
    4776      242608 :             for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
    4777      241664 :                 if (RmgrIdExists(rmid) && GetRmgr(rmid).rm_mask != NULL)
    4778        9440 :                     newwalconsistency[rmid] = true;
    4779             :         }
    4780             :         else
    4781             :         {
    4782             :             /* Check if the token matches any known resource manager. */
    4783           4 :             bool        found = false;
    4784             : 
    4785          72 :             for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
    4786             :             {
    4787         108 :                 if (RmgrIdExists(rmid) && GetRmgr(rmid).rm_mask != NULL &&
    4788          36 :                     pg_strcasecmp(tok, GetRmgr(rmid).rm_name) == 0)
    4789             :                 {
    4790           4 :                     newwalconsistency[rmid] = true;
    4791           4 :                     found = true;
    4792           4 :                     break;
    4793             :                 }
    4794             :             }
    4795           4 :             if (!found)
    4796             :             {
    4797             :                 /*
    4798             :                  * During startup, it might be a not-yet-loaded custom
    4799             :                  * resource manager.  Defer checking until
    4800             :                  * InitializeWalConsistencyChecking().
    4801             :                  */
    4802           0 :                 if (!process_shared_preload_libraries_done)
    4803             :                 {
    4804           0 :                     check_wal_consistency_checking_deferred = true;
    4805             :                 }
    4806             :                 else
    4807             :                 {
    4808           0 :                     GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
    4809           0 :                     pfree(rawstring);
    4810           0 :                     list_free(elemlist);
    4811           0 :                     return false;
    4812             :                 }
    4813             :             }
    4814             :         }
    4815             :     }
    4816             : 
    4817        4230 :     pfree(rawstring);
    4818        4230 :     list_free(elemlist);
    4819             : 
    4820             :     /* assign new value */
    4821        4230 :     *extra = guc_malloc(LOG, (RM_MAX_ID + 1) * sizeof(bool));
    4822        4230 :     if (!*extra)
    4823           0 :         return false;
    4824        4230 :     memcpy(*extra, newwalconsistency, (RM_MAX_ID + 1) * sizeof(bool));
    4825        4230 :     return true;
    4826             : }
    4827             : 
    4828             : /*
    4829             :  * GUC assign_hook for wal_consistency_checking
    4830             :  */
    4831             : void
    4832        4228 : assign_wal_consistency_checking(const char *newval, void *extra)
    4833             : {
    4834             :     /*
    4835             :      * If some checks were deferred, it's possible that the checks will fail
    4836             :      * later during InitializeWalConsistencyChecking(). But in that case, the
    4837             :      * postmaster will exit anyway, so it's safe to proceed with the
    4838             :      * assignment.
    4839             :      *
    4840             :      * Any built-in resource managers specified are assigned immediately,
    4841             :      * which affects WAL created before shared_preload_libraries are
    4842             :      * processed. Any custom resource managers specified won't be assigned
    4843             :      * until after shared_preload_libraries are processed, but that's OK
    4844             :      * because WAL for a custom resource manager can't be written before the
    4845             :      * module is loaded anyway.
    4846             :      */
    4847        4228 :     wal_consistency_checking = extra;
    4848        4228 : }
    4849             : 
    4850             : /*
    4851             :  * InitializeWalConsistencyChecking: run after loading custom resource managers
    4852             :  *
    4853             :  * If any unknown resource managers were specified in the
    4854             :  * wal_consistency_checking GUC, processing was deferred.  Now that
    4855             :  * shared_preload_libraries have been loaded, process wal_consistency_checking
    4856             :  * again.
    4857             :  */
    4858             : void
    4859        1962 : InitializeWalConsistencyChecking(void)
    4860             : {
    4861             :     Assert(process_shared_preload_libraries_done);
    4862             : 
    4863        1962 :     if (check_wal_consistency_checking_deferred)
    4864             :     {
    4865             :         struct config_generic *guc;
    4866             : 
    4867           0 :         guc = find_option("wal_consistency_checking", false, false, ERROR);
    4868             : 
    4869           0 :         check_wal_consistency_checking_deferred = false;
    4870             : 
    4871           0 :         set_config_option_ext("wal_consistency_checking",
    4872             :                               wal_consistency_checking_string,
    4873             :                               guc->scontext, guc->source, guc->srole,
    4874             :                               GUC_ACTION_SET, true, ERROR, false);
    4875             : 
    4876             :         /* checking should not be deferred again */
    4877             :         Assert(!check_wal_consistency_checking_deferred);
    4878             :     }
    4879        1962 : }
    4880             : 
    4881             : /*
    4882             :  * GUC show_hook for archive_command
    4883             :  */
    4884             : const char *
    4885        3452 : show_archive_command(void)
    4886             : {
    4887        3452 :     if (XLogArchivingActive())
    4888           4 :         return XLogArchiveCommand;
    4889             :     else
    4890        3448 :         return "(disabled)";
    4891             : }
    4892             : 
    4893             : /*
    4894             :  * GUC show_hook for in_hot_standby
    4895             :  */
    4896             : const char *
    4897       31720 : show_in_hot_standby(void)
    4898             : {
    4899             :     /*
    4900             :      * We display the actual state based on shared memory, so that this GUC
    4901             :      * reports up-to-date state if examined intra-query.  The underlying
    4902             :      * variable (in_hot_standby_guc) changes only when we transmit a new value
    4903             :      * to the client.
    4904             :      */
    4905       31720 :     return RecoveryInProgress() ? "on" : "off";
    4906             : }
    4907             : 
    4908             : /*
    4909             :  * GUC show_hook for effective_wal_level
    4910             :  */
    4911             : const char *
    4912        3516 : show_effective_wal_level(void)
    4913             : {
    4914        3516 :     if (wal_level == WAL_LEVEL_MINIMAL)
    4915         392 :         return "minimal";
    4916             : 
    4917             :     /*
    4918             :      * During recovery, effective_wal_level reflects the primary's
    4919             :      * configuration rather than the local wal_level value.
    4920             :      */
    4921        3124 :     if (RecoveryInProgress())
    4922          44 :         return IsXLogLogicalInfoEnabled() ? "logical" : "replica";
    4923             : 
    4924        3080 :     return XLogLogicalInfoActive() ? "logical" : "replica";
    4925             : }
    4926             : 
    4927             : /*
    4928             :  * Read the control file, set respective GUCs.
    4929             :  *
    4930             :  * This is to be called during startup, including a crash recovery cycle,
    4931             :  * unless in bootstrap mode, where no control file yet exists.  As there's no
    4932             :  * usable shared memory yet (its sizing can depend on the contents of the
    4933             :  * control file!), first store the contents in local memory. XLOGShmemInit()
    4934             :  * will then copy it to shared memory later.
    4935             :  *
    4936             :  * reset just controls whether previous contents are to be expected (in the
    4937             :  * reset case, there's a dangling pointer into old shared memory), or not.
    4938             :  */
    4939             : void
    4940        1982 : LocalProcessControlFile(bool reset)
    4941             : {
    4942             :     Assert(reset || ControlFile == NULL);
    4943        1982 :     ControlFile = palloc_object(ControlFileData);
    4944        1982 :     ReadControlFile();
    4945        1982 : }
    4946             : 
    4947             : /*
    4948             :  * Get the wal_level from the control file. For a standby, this value should be
    4949             :  * considered as its active wal_level, because it may be different from what
    4950             :  * was originally configured on standby.
    4951             :  */
    4952             : WalLevel
    4953           0 : GetActiveWalLevelOnStandby(void)
    4954             : {
    4955           0 :     return ControlFile->wal_level;
    4956             : }
    4957             : 
    4958             : /*
    4959             :  * Initialization of shared memory for XLOG
    4960             :  */
    4961             : Size
    4962        6510 : XLOGShmemSize(void)
    4963             : {
    4964             :     Size        size;
    4965             : 
    4966             :     /*
    4967             :      * If the value of wal_buffers is -1, use the preferred auto-tune value.
    4968             :      * This isn't an amazingly clean place to do this, but we must wait till
    4969             :      * NBuffers has received its final value, and must do it before using the
    4970             :      * value of XLOGbuffers to do anything important.
    4971             :      *
    4972             :      * We prefer to report this value's source as PGC_S_DYNAMIC_DEFAULT.
    4973             :      * However, if the DBA explicitly set wal_buffers = -1 in the config file,
    4974             :      * then PGC_S_DYNAMIC_DEFAULT will fail to override that and we must force
    4975             :      * the matter with PGC_S_OVERRIDE.
    4976             :      */
    4977        6510 :     if (XLOGbuffers == -1)
    4978             :     {
    4979             :         char        buf[32];
    4980             : 
    4981        2268 :         snprintf(buf, sizeof(buf), "%d", XLOGChooseNumBuffers());
    4982        2268 :         SetConfigOption("wal_buffers", buf, PGC_POSTMASTER,
    4983             :                         PGC_S_DYNAMIC_DEFAULT);
    4984        2268 :         if (XLOGbuffers == -1)  /* failed to apply it? */
    4985           0 :             SetConfigOption("wal_buffers", buf, PGC_POSTMASTER,
    4986             :                             PGC_S_OVERRIDE);
    4987             :     }
    4988             :     Assert(XLOGbuffers > 0);
    4989             : 
    4990             :     /* XLogCtl */
    4991        6510 :     size = sizeof(XLogCtlData);
    4992             : 
    4993             :     /* WAL insertion locks, plus alignment */
    4994        6510 :     size = add_size(size, mul_size(sizeof(WALInsertLockPadded), NUM_XLOGINSERT_LOCKS + 1));
    4995             :     /* xlblocks array */
    4996        6510 :     size = add_size(size, mul_size(sizeof(pg_atomic_uint64), XLOGbuffers));
    4997             :     /* extra alignment padding for XLOG I/O buffers */
    4998        6510 :     size = add_size(size, Max(XLOG_BLCKSZ, PG_IO_ALIGN_SIZE));
    4999             :     /* and the buffers themselves */
    5000        6510 :     size = add_size(size, mul_size(XLOG_BLCKSZ, XLOGbuffers));
    5001             : 
    5002             :     /*
    5003             :      * Note: we don't count ControlFileData, it comes out of the "slop factor"
    5004             :      * added by CreateSharedMemoryAndSemaphores.  This lets us use this
    5005             :      * routine again below to compute the actual allocation size.
    5006             :      */
    5007             : 
    5008        6510 :     return size;
    5009             : }
    5010             : 
    5011             : void
    5012        2272 : XLOGShmemInit(void)
    5013             : {
    5014             :     bool        foundCFile,
    5015             :                 foundXLog;
    5016             :     char       *allocptr;
    5017             :     int         i;
    5018             :     ControlFileData *localControlFile;
    5019             : 
    5020             : #ifdef WAL_DEBUG
    5021             : 
    5022             :     /*
    5023             :      * Create a memory context for WAL debugging that's exempt from the normal
    5024             :      * "no pallocs in critical section" rule. Yes, that can lead to a PANIC if
    5025             :      * an allocation fails, but wal_debug is not for production use anyway.
    5026             :      */
    5027             :     if (walDebugCxt == NULL)
    5028             :     {
    5029             :         walDebugCxt = AllocSetContextCreate(TopMemoryContext,
    5030             :                                             "WAL Debug",
    5031             :                                             ALLOCSET_DEFAULT_SIZES);
    5032             :         MemoryContextAllowInCriticalSection(walDebugCxt, true);
    5033             :     }
    5034             : #endif
    5035             : 
    5036             : 
    5037        2272 :     XLogCtl = (XLogCtlData *)
    5038        2272 :         ShmemInitStruct("XLOG Ctl", XLOGShmemSize(), &foundXLog);
    5039             : 
    5040        2272 :     localControlFile = ControlFile;
    5041        2272 :     ControlFile = (ControlFileData *)
    5042        2272 :         ShmemInitStruct("Control File", sizeof(ControlFileData), &foundCFile);
    5043             : 
    5044        2272 :     if (foundCFile || foundXLog)
    5045             :     {
    5046             :         /* both should be present or neither */
    5047             :         Assert(foundCFile && foundXLog);
    5048             : 
    5049             :         /* Initialize local copy of WALInsertLocks */
    5050           0 :         WALInsertLocks = XLogCtl->Insert.WALInsertLocks;
    5051             : 
    5052           0 :         if (localControlFile)
    5053           0 :             pfree(localControlFile);
    5054           0 :         return;
    5055             :     }
    5056        2272 :     memset(XLogCtl, 0, sizeof(XLogCtlData));
    5057             : 
    5058             :     /*
    5059             :      * Already have read control file locally, unless in bootstrap mode. Move
    5060             :      * contents into shared memory.
    5061             :      */
    5062        2272 :     if (localControlFile)
    5063             :     {
    5064        1966 :         memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
    5065        1966 :         pfree(localControlFile);
    5066             :     }
    5067             : 
    5068             :     /*
    5069             :      * Since XLogCtlData contains XLogRecPtr fields, its sizeof should be a
    5070             :      * multiple of the alignment for same, so no extra alignment padding is
    5071             :      * needed here.
    5072             :      */
    5073        2272 :     allocptr = ((char *) XLogCtl) + sizeof(XLogCtlData);
    5074        2272 :     XLogCtl->xlblocks = (pg_atomic_uint64 *) allocptr;
    5075        2272 :     allocptr += sizeof(pg_atomic_uint64) * XLOGbuffers;
    5076             : 
    5077      650490 :     for (i = 0; i < XLOGbuffers; i++)
    5078             :     {
    5079      648218 :         pg_atomic_init_u64(&XLogCtl->xlblocks[i], InvalidXLogRecPtr);
    5080             :     }
    5081             : 
    5082             :     /* WAL insertion locks. Ensure they're aligned to the full padded size */
    5083        2272 :     allocptr += sizeof(WALInsertLockPadded) -
    5084        2272 :         ((uintptr_t) allocptr) % sizeof(WALInsertLockPadded);
    5085        2272 :     WALInsertLocks = XLogCtl->Insert.WALInsertLocks =
    5086             :         (WALInsertLockPadded *) allocptr;
    5087        2272 :     allocptr += sizeof(WALInsertLockPadded) * NUM_XLOGINSERT_LOCKS;
    5088             : 
    5089       20448 :     for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++)
    5090             :     {
    5091       18176 :         LWLockInitialize(&WALInsertLocks[i].l.lock, LWTRANCHE_WAL_INSERT);
    5092       18176 :         pg_atomic_init_u64(&WALInsertLocks[i].l.insertingAt, InvalidXLogRecPtr);
    5093       18176 :         WALInsertLocks[i].l.lastImportantAt = InvalidXLogRecPtr;
    5094             :     }
    5095             : 
    5096             :     /*
    5097             :      * Align the start of the page buffers to a full xlog block size boundary.
    5098             :      * This simplifies some calculations in XLOG insertion. It is also
    5099             :      * required for O_DIRECT.
    5100             :      */
    5101        2272 :     allocptr = (char *) TYPEALIGN(XLOG_BLCKSZ, allocptr);
    5102        2272 :     XLogCtl->pages = allocptr;
    5103        2272 :     memset(XLogCtl->pages, 0, (Size) XLOG_BLCKSZ * XLOGbuffers);
    5104             : 
    5105             :     /*
    5106             :      * Do basic initialization of XLogCtl shared data. (StartupXLOG will fill
    5107             :      * in additional info.)
    5108             :      */
    5109        2272 :     XLogCtl->XLogCacheBlck = XLOGbuffers - 1;
    5110        2272 :     XLogCtl->SharedRecoveryState = RECOVERY_STATE_CRASH;
    5111        2272 :     XLogCtl->InstallXLogFileSegmentActive = false;
    5112        2272 :     XLogCtl->WalWriterSleeping = false;
    5113             : 
    5114        2272 :     SpinLockInit(&XLogCtl->Insert.insertpos_lck);
    5115        2272 :     SpinLockInit(&XLogCtl->info_lck);
    5116        2272 :     pg_atomic_init_u64(&XLogCtl->logInsertResult, InvalidXLogRecPtr);
    5117        2272 :     pg_atomic_init_u64(&XLogCtl->logWriteResult, InvalidXLogRecPtr);
    5118        2272 :     pg_atomic_init_u64(&XLogCtl->logFlushResult, InvalidXLogRecPtr);
    5119        2272 :     pg_atomic_init_u64(&XLogCtl->unloggedLSN, InvalidXLogRecPtr);
    5120             : }
    5121             : 
    5122             : /*
    5123             :  * This func must be called ONCE on system install.  It creates pg_control
    5124             :  * and the initial XLOG segment.
    5125             :  */
    5126             : void
    5127         102 : BootStrapXLOG(uint32 data_checksum_version)
    5128             : {
    5129             :     CheckPoint  checkPoint;
    5130             :     PGAlignedXLogBlock buffer;
    5131             :     XLogPageHeader page;
    5132             :     XLogLongPageHeader longpage;
    5133             :     XLogRecord *record;
    5134             :     char       *recptr;
    5135             :     uint64      sysidentifier;
    5136             :     struct timeval tv;
    5137             :     pg_crc32c   crc;
    5138             : 
    5139             :     /* allow ordinary WAL segment creation, like StartupXLOG() would */
    5140         102 :     SetInstallXLogFileSegmentActive();
    5141             : 
    5142             :     /*
    5143             :      * Select a hopefully-unique system identifier code for this installation.
    5144             :      * We use the result of gettimeofday(), including the fractional seconds
    5145             :      * field, as being about as unique as we can easily get.  (Think not to
    5146             :      * use random(), since it hasn't been seeded and there's no portable way
    5147             :      * to seed it other than the system clock value...)  The upper half of the
    5148             :      * uint64 value is just the tv_sec part, while the lower half contains the
    5149             :      * tv_usec part (which must fit in 20 bits), plus 12 bits from our current
    5150             :      * PID for a little extra uniqueness.  A person knowing this encoding can
    5151             :      * determine the initialization time of the installation, which could
    5152             :      * perhaps be useful sometimes.
    5153             :      */
    5154         102 :     gettimeofday(&tv, NULL);
    5155         102 :     sysidentifier = ((uint64) tv.tv_sec) << 32;
    5156         102 :     sysidentifier |= ((uint64) tv.tv_usec) << 12;
    5157         102 :     sysidentifier |= getpid() & 0xFFF;
    5158             : 
    5159         102 :     memset(&buffer, 0, sizeof buffer);
    5160         102 :     page = (XLogPageHeader) &buffer;
    5161             : 
    5162             :     /*
    5163             :      * Set up information for the initial checkpoint record
    5164             :      *
    5165             :      * The initial checkpoint record is written to the beginning of the WAL
    5166             :      * segment with logid=0 logseg=1. The very first WAL segment, 0/0, is not
    5167             :      * used, so that we can use 0/0 to mean "before any valid WAL segment".
    5168             :      */
    5169         102 :     checkPoint.redo = wal_segment_size + SizeOfXLogLongPHD;
    5170         102 :     checkPoint.ThisTimeLineID = BootstrapTimeLineID;
    5171         102 :     checkPoint.PrevTimeLineID = BootstrapTimeLineID;
    5172         102 :     checkPoint.fullPageWrites = fullPageWrites;
    5173         102 :     checkPoint.logicalDecodingEnabled = (wal_level == WAL_LEVEL_LOGICAL);
    5174         102 :     checkPoint.wal_level = wal_level;
    5175             :     checkPoint.nextXid =
    5176         102 :         FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId);
    5177         102 :     checkPoint.nextOid = FirstGenbkiObjectId;
    5178         102 :     checkPoint.nextMulti = FirstMultiXactId;
    5179         102 :     checkPoint.nextMultiOffset = 1;
    5180         102 :     checkPoint.oldestXid = FirstNormalTransactionId;
    5181         102 :     checkPoint.oldestXidDB = Template1DbOid;
    5182         102 :     checkPoint.oldestMulti = FirstMultiXactId;
    5183         102 :     checkPoint.oldestMultiDB = Template1DbOid;
    5184         102 :     checkPoint.oldestCommitTsXid = InvalidTransactionId;
    5185         102 :     checkPoint.newestCommitTsXid = InvalidTransactionId;
    5186         102 :     checkPoint.time = (pg_time_t) time(NULL);
    5187         102 :     checkPoint.oldestActiveXid = InvalidTransactionId;
    5188             : 
    5189         102 :     TransamVariables->nextXid = checkPoint.nextXid;
    5190         102 :     TransamVariables->nextOid = checkPoint.nextOid;
    5191         102 :     TransamVariables->oidCount = 0;
    5192         102 :     MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset);
    5193         102 :     AdvanceOldestClogXid(checkPoint.oldestXid);
    5194         102 :     SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
    5195         102 :     SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB);
    5196         102 :     SetCommitTsLimit(InvalidTransactionId, InvalidTransactionId);
    5197             : 
    5198             :     /* Set up the XLOG page header */
    5199         102 :     page->xlp_magic = XLOG_PAGE_MAGIC;
    5200         102 :     page->xlp_info = XLP_LONG_HEADER;
    5201         102 :     page->xlp_tli = BootstrapTimeLineID;
    5202         102 :     page->xlp_pageaddr = wal_segment_size;
    5203         102 :     longpage = (XLogLongPageHeader) page;
    5204         102 :     longpage->xlp_sysid = sysidentifier;
    5205         102 :     longpage->xlp_seg_size = wal_segment_size;
    5206         102 :     longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
    5207             : 
    5208             :     /* Insert the initial checkpoint record */
    5209         102 :     recptr = ((char *) page + SizeOfXLogLongPHD);
    5210         102 :     record = (XLogRecord *) recptr;
    5211         102 :     record->xl_prev = 0;
    5212         102 :     record->xl_xid = InvalidTransactionId;
    5213         102 :     record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(checkPoint);
    5214         102 :     record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
    5215         102 :     record->xl_rmid = RM_XLOG_ID;
    5216         102 :     recptr += SizeOfXLogRecord;
    5217             :     /* fill the XLogRecordDataHeaderShort struct */
    5218         102 :     *(recptr++) = (char) XLR_BLOCK_ID_DATA_SHORT;
    5219         102 :     *(recptr++) = sizeof(checkPoint);
    5220         102 :     memcpy(recptr, &checkPoint, sizeof(checkPoint));
    5221         102 :     recptr += sizeof(checkPoint);
    5222             :     Assert(recptr - (char *) record == record->xl_tot_len);
    5223             : 
    5224         102 :     INIT_CRC32C(crc);
    5225         102 :     COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
    5226         102 :     COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
    5227         102 :     FIN_CRC32C(crc);
    5228         102 :     record->xl_crc = crc;
    5229             : 
    5230             :     /* Create first XLOG segment file */
    5231         102 :     openLogTLI = BootstrapTimeLineID;
    5232         102 :     openLogFile = XLogFileInit(1, BootstrapTimeLineID);
    5233             : 
    5234             :     /*
    5235             :      * We needn't bother with Reserve/ReleaseExternalFD here, since we'll
    5236             :      * close the file again in a moment.
    5237             :      */
    5238             : 
    5239             :     /* Write the first page with the initial record */
    5240         102 :     errno = 0;
    5241         102 :     pgstat_report_wait_start(WAIT_EVENT_WAL_BOOTSTRAP_WRITE);
    5242         102 :     if (write(openLogFile, &buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
    5243             :     {
    5244             :         /* if write didn't set errno, assume problem is no disk space */
    5245           0 :         if (errno == 0)
    5246           0 :             errno = ENOSPC;
    5247           0 :         ereport(PANIC,
    5248             :                 (errcode_for_file_access(),
    5249             :                  errmsg("could not write bootstrap write-ahead log file: %m")));
    5250             :     }
    5251         102 :     pgstat_report_wait_end();
    5252             : 
    5253         102 :     pgstat_report_wait_start(WAIT_EVENT_WAL_BOOTSTRAP_SYNC);
    5254         102 :     if (pg_fsync(openLogFile) != 0)
    5255           0 :         ereport(PANIC,
    5256             :                 (errcode_for_file_access(),
    5257             :                  errmsg("could not fsync bootstrap write-ahead log file: %m")));
    5258         102 :     pgstat_report_wait_end();
    5259             : 
    5260         102 :     if (close(openLogFile) != 0)
    5261           0 :         ereport(PANIC,
    5262             :                 (errcode_for_file_access(),
    5263             :                  errmsg("could not close bootstrap write-ahead log file: %m")));
    5264             : 
    5265         102 :     openLogFile = -1;
    5266             : 
    5267             :     /* Now create pg_control */
    5268         102 :     InitControlFile(sysidentifier, data_checksum_version);
    5269         102 :     ControlFile->time = checkPoint.time;
    5270         102 :     ControlFile->checkPoint = checkPoint.redo;
    5271         102 :     ControlFile->checkPointCopy = checkPoint;
    5272             : 
    5273             :     /* some additional ControlFile fields are set in WriteControlFile() */
    5274         102 :     WriteControlFile();
    5275             : 
    5276             :     /* Bootstrap the commit log, too */
    5277         102 :     BootStrapCLOG();
    5278         102 :     BootStrapCommitTs();
    5279         102 :     BootStrapSUBTRANS();
    5280         102 :     BootStrapMultiXact();
    5281             : 
    5282             :     /*
    5283             :      * Force control file to be read - in contrast to normal processing we'd
    5284             :      * otherwise never run the checks and GUC related initializations therein.
    5285             :      */
    5286         102 :     ReadControlFile();
    5287         102 : }
    5288             : 
    5289             : static char *
    5290        1758 : str_time(pg_time_t tnow, char *buf, size_t bufsize)
    5291             : {
    5292        1758 :     pg_strftime(buf, bufsize,
    5293             :                 "%Y-%m-%d %H:%M:%S %Z",
    5294        1758 :                 pg_localtime(&tnow, log_timezone));
    5295             : 
    5296        1758 :     return buf;
    5297             : }
    5298             : 
    5299             : /*
    5300             :  * Initialize the first WAL segment on new timeline.
    5301             :  */
    5302             : static void
    5303         110 : XLogInitNewTimeline(TimeLineID endTLI, XLogRecPtr endOfLog, TimeLineID newTLI)
    5304             : {
    5305             :     char        xlogfname[MAXFNAMELEN];
    5306             :     XLogSegNo   endLogSegNo;
    5307             :     XLogSegNo   startLogSegNo;
    5308             : 
    5309             :     /* we always switch to a new timeline after archive recovery */
    5310             :     Assert(endTLI != newTLI);
    5311             : 
    5312             :     /*
    5313             :      * Update min recovery point one last time.
    5314             :      */
    5315         110 :     UpdateMinRecoveryPoint(InvalidXLogRecPtr, true);
    5316             : 
    5317             :     /*
    5318             :      * Calculate the last segment on the old timeline, and the first segment
    5319             :      * on the new timeline. If the switch happens in the middle of a segment,
    5320             :      * they are the same, but if the switch happens exactly at a segment
    5321             :      * boundary, startLogSegNo will be endLogSegNo + 1.
    5322             :      */
    5323         110 :     XLByteToPrevSeg(endOfLog, endLogSegNo, wal_segment_size);
    5324         110 :     XLByteToSeg(endOfLog, startLogSegNo, wal_segment_size);
    5325             : 
    5326             :     /*
    5327             :      * Initialize the starting WAL segment for the new timeline. If the switch
    5328             :      * happens in the middle of a segment, copy data from the last WAL segment
    5329             :      * of the old timeline up to the switch point, to the starting WAL segment
    5330             :      * on the new timeline.
    5331             :      */
    5332         110 :     if (endLogSegNo == startLogSegNo)
    5333             :     {
    5334             :         /*
    5335             :          * Make a copy of the file on the new timeline.
    5336             :          *
    5337             :          * Writing WAL isn't allowed yet, so there are no locking
    5338             :          * considerations. But we should be just as tense as XLogFileInit to
    5339             :          * avoid emplacing a bogus file.
    5340             :          */
    5341          90 :         XLogFileCopy(newTLI, endLogSegNo, endTLI, endLogSegNo,
    5342          90 :                      XLogSegmentOffset(endOfLog, wal_segment_size));
    5343             :     }
    5344             :     else
    5345             :     {
    5346             :         /*
    5347             :          * The switch happened at a segment boundary, so just create the next
    5348             :          * segment on the new timeline.
    5349             :          */
    5350             :         int         fd;
    5351             : 
    5352          20 :         fd = XLogFileInit(startLogSegNo, newTLI);
    5353             : 
    5354          20 :         if (close(fd) != 0)
    5355             :         {
    5356           0 :             int         save_errno = errno;
    5357             : 
    5358           0 :             XLogFileName(xlogfname, newTLI, startLogSegNo, wal_segment_size);
    5359           0 :             errno = save_errno;
    5360           0 :             ereport(ERROR,
    5361             :                     (errcode_for_file_access(),
    5362             :                      errmsg("could not close file \"%s\": %m", xlogfname)));
    5363             :         }
    5364             :     }
    5365             : 
    5366             :     /*
    5367             :      * Let's just make real sure there are not .ready or .done flags posted
    5368             :      * for the new segment.
    5369             :      */
    5370         110 :     XLogFileName(xlogfname, newTLI, startLogSegNo, wal_segment_size);
    5371         110 :     XLogArchiveCleanup(xlogfname);
    5372         110 : }
    5373             : 
    5374             : /*
    5375             :  * Perform cleanup actions at the conclusion of archive recovery.
    5376             :  */
    5377             : static void
    5378         110 : CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog,
    5379             :                             TimeLineID newTLI)
    5380             : {
    5381             :     /*
    5382             :      * Execute the recovery_end_command, if any.
    5383             :      */
    5384         110 :     if (recoveryEndCommand && strcmp(recoveryEndCommand, "") != 0)
    5385           4 :         ExecuteRecoveryCommand(recoveryEndCommand,
    5386             :                                "recovery_end_command",
    5387             :                                true,
    5388             :                                WAIT_EVENT_RECOVERY_END_COMMAND);
    5389             : 
    5390             :     /*
    5391             :      * We switched to a new timeline. Clean up segments on the old timeline.
    5392             :      *
    5393             :      * If there are any higher-numbered segments on the old timeline, remove
    5394             :      * them. They might contain valid WAL, but they might also be
    5395             :      * pre-allocated files containing garbage. In any case, they are not part
    5396             :      * of the new timeline's history so we don't need them.
    5397             :      */
    5398         110 :     RemoveNonParentXlogFiles(EndOfLog, newTLI);
    5399             : 
    5400             :     /*
    5401             :      * If the switch happened in the middle of a segment, what to do with the
    5402             :      * last, partial segment on the old timeline? If we don't archive it, and
    5403             :      * the server that created the WAL never archives it either (e.g. because
    5404             :      * it was hit by a meteor), it will never make it to the archive. That's
    5405             :      * OK from our point of view, because the new segment that we created with
    5406             :      * the new TLI contains all the WAL from the old timeline up to the switch
    5407             :      * point. But if you later try to do PITR to the "missing" WAL on the old
    5408             :      * timeline, recovery won't find it in the archive. It's physically
    5409             :      * present in the new file with new TLI, but recovery won't look there
    5410             :      * when it's recovering to the older timeline. On the other hand, if we
    5411             :      * archive the partial segment, and the original server on that timeline
    5412             :      * is still running and archives the completed version of the same segment
    5413             :      * later, it will fail. (We used to do that in 9.4 and below, and it
    5414             :      * caused such problems).
    5415             :      *
    5416             :      * As a compromise, we rename the last segment with the .partial suffix,
    5417             :      * and archive it. Archive recovery will never try to read .partial
    5418             :      * segments, so they will normally go unused. But in the odd PITR case,
    5419             :      * the administrator can copy them manually to the pg_wal directory
    5420             :      * (removing the suffix). They can be useful in debugging, too.
    5421             :      *
    5422             :      * If a .done or .ready file already exists for the old timeline, however,
    5423             :      * we had already determined that the segment is complete, so we can let
    5424             :      * it be archived normally. (In particular, if it was restored from the
    5425             :      * archive to begin with, it's expected to have a .done file).
    5426             :      */
    5427         110 :     if (XLogSegmentOffset(EndOfLog, wal_segment_size) != 0 &&
    5428             :         XLogArchivingActive())
    5429             :     {
    5430             :         char        origfname[MAXFNAMELEN];
    5431             :         XLogSegNo   endLogSegNo;
    5432             : 
    5433          20 :         XLByteToPrevSeg(EndOfLog, endLogSegNo, wal_segment_size);
    5434          20 :         XLogFileName(origfname, EndOfLogTLI, endLogSegNo, wal_segment_size);
    5435             : 
    5436          20 :         if (!XLogArchiveIsReadyOrDone(origfname))
    5437             :         {
    5438             :             char        origpath[MAXPGPATH];
    5439             :             char        partialfname[MAXFNAMELEN];
    5440             :             char        partialpath[MAXPGPATH];
    5441             : 
    5442             :             /*
    5443             :              * If we're summarizing WAL, we can't rename the partial file
    5444             :              * until the summarizer finishes with it, else it will fail.
    5445             :              */
    5446          12 :             if (summarize_wal)
    5447           2 :                 WaitForWalSummarization(EndOfLog);
    5448             : 
    5449          12 :             XLogFilePath(origpath, EndOfLogTLI, endLogSegNo, wal_segment_size);
    5450          12 :             snprintf(partialfname, MAXFNAMELEN, "%s.partial", origfname);
    5451          12 :             snprintf(partialpath, MAXPGPATH, "%s.partial", origpath);
    5452             : 
    5453             :             /*
    5454             :              * Make sure there's no .done or .ready file for the .partial
    5455             :              * file.
    5456             :              */
    5457          12 :             XLogArchiveCleanup(partialfname);
    5458             : 
    5459          12 :             durable_rename(origpath, partialpath, ERROR);
    5460          12 :             XLogArchiveNotify(partialfname);
    5461             :         }
    5462             :     }
    5463         110 : }
    5464             : 
    5465             : /*
    5466             :  * Check to see if required parameters are set high enough on this server
    5467             :  * for various aspects of recovery operation.
    5468             :  *
    5469             :  * Note that all the parameters which this function tests need to be
    5470             :  * listed in Administrator's Overview section in high-availability.sgml.
    5471             :  * If you change them, don't forget to update the list.
    5472             :  */
    5473             : static void
    5474         520 : CheckRequiredParameterValues(void)
    5475             : {
    5476             :     /*
    5477             :      * For archive recovery, the WAL must be generated with at least 'replica'
    5478             :      * wal_level.
    5479             :      */
    5480         520 :     if (ArchiveRecoveryRequested && ControlFile->wal_level == WAL_LEVEL_MINIMAL)
    5481             :     {
    5482           4 :         ereport(FATAL,
    5483             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    5484             :                  errmsg("WAL was generated with \"wal_level=minimal\", cannot continue recovering"),
    5485             :                  errdetail("This happens if you temporarily set \"wal_level=minimal\" on the server."),
    5486             :                  errhint("Use a backup taken after setting \"wal_level\" to higher than \"minimal\".")));
    5487             :     }
    5488             : 
    5489             :     /*
    5490             :      * For Hot Standby, the WAL must be generated with 'replica' mode, and we
    5491             :      * must have at least as many backend slots as the primary.
    5492             :      */
    5493         516 :     if (ArchiveRecoveryRequested && EnableHotStandby)
    5494             :     {
    5495             :         /* We ignore autovacuum_worker_slots when we make this test. */
    5496         270 :         RecoveryRequiresIntParameter("max_connections",
    5497             :                                      MaxConnections,
    5498         270 :                                      ControlFile->MaxConnections);
    5499         270 :         RecoveryRequiresIntParameter("max_worker_processes",
    5500             :                                      max_worker_processes,
    5501         270 :                                      ControlFile->max_worker_processes);
    5502         270 :         RecoveryRequiresIntParameter("max_wal_senders",
    5503             :                                      max_wal_senders,
    5504         270 :                                      ControlFile->max_wal_senders);
    5505         270 :         RecoveryRequiresIntParameter("max_prepared_transactions",
    5506             :                                      max_prepared_xacts,
    5507         270 :                                      ControlFile->max_prepared_xacts);
    5508         270 :         RecoveryRequiresIntParameter("max_locks_per_transaction",
    5509             :                                      max_locks_per_xact,
    5510         270 :                                      ControlFile->max_locks_per_xact);
    5511             :     }
    5512         516 : }
    5513             : 
    5514             : /*
    5515             :  * This must be called ONCE during postmaster or standalone-backend startup
    5516             :  */
    5517             : void
    5518        1982 : StartupXLOG(void)
    5519             : {
    5520             :     XLogCtlInsert *Insert;
    5521             :     CheckPoint  checkPoint;
    5522             :     bool        wasShutdown;
    5523             :     bool        didCrash;
    5524             :     bool        haveTblspcMap;
    5525             :     bool        haveBackupLabel;
    5526             :     XLogRecPtr  EndOfLog;
    5527             :     TimeLineID  EndOfLogTLI;
    5528             :     TimeLineID  newTLI;
    5529             :     bool        performedWalRecovery;
    5530             :     EndOfWalRecoveryInfo *endOfRecoveryInfo;
    5531             :     XLogRecPtr  abortedRecPtr;
    5532             :     XLogRecPtr  missingContrecPtr;
    5533             :     TransactionId oldestActiveXID;
    5534        1982 :     bool        promoted = false;
    5535             :     char        timebuf[128];
    5536             : 
    5537             :     /*
    5538             :      * We should have an aux process resource owner to use, and we should not
    5539             :      * be in a transaction that's installed some other resowner.
    5540             :      */
    5541             :     Assert(AuxProcessResourceOwner != NULL);
    5542             :     Assert(CurrentResourceOwner == NULL ||
    5543             :            CurrentResourceOwner == AuxProcessResourceOwner);
    5544        1982 :     CurrentResourceOwner = AuxProcessResourceOwner;
    5545             : 
    5546             :     /*
    5547             :      * Check that contents look valid.
    5548             :      */
    5549        1982 :     if (!XRecOffIsValid(ControlFile->checkPoint))
    5550           0 :         ereport(FATAL,
    5551             :                 (errcode(ERRCODE_DATA_CORRUPTED),
    5552             :                  errmsg("control file contains invalid checkpoint location")));
    5553             : 
    5554        1982 :     switch (ControlFile->state)
    5555             :     {
    5556        1548 :         case DB_SHUTDOWNED:
    5557             : 
    5558             :             /*
    5559             :              * This is the expected case, so don't be chatty in standalone
    5560             :              * mode
    5561             :              */
    5562        1548 :             ereport(IsPostmasterEnvironment ? LOG : NOTICE,
    5563             :                     (errmsg("database system was shut down at %s",
    5564             :                             str_time(ControlFile->time,
    5565             :                                      timebuf, sizeof(timebuf)))));
    5566        1548 :             break;
    5567             : 
    5568          66 :         case DB_SHUTDOWNED_IN_RECOVERY:
    5569          66 :             ereport(LOG,
    5570             :                     (errmsg("database system was shut down in recovery at %s",
    5571             :                             str_time(ControlFile->time,
    5572             :                                      timebuf, sizeof(timebuf)))));
    5573          66 :             break;
    5574             : 
    5575           0 :         case DB_SHUTDOWNING:
    5576           0 :             ereport(LOG,
    5577             :                     (errmsg("database system shutdown was interrupted; last known up at %s",
    5578             :                             str_time(ControlFile->time,
    5579             :                                      timebuf, sizeof(timebuf)))));
    5580           0 :             break;
    5581             : 
    5582           0 :         case DB_IN_CRASH_RECOVERY:
    5583           0 :             ereport(LOG,
    5584             :                     (errmsg("database system was interrupted while in recovery at %s",
    5585             :                             str_time(ControlFile->time,
    5586             :                                      timebuf, sizeof(timebuf))),
    5587             :                      errhint("This probably means that some data is corrupted and"
    5588             :                              " you will have to use the last backup for recovery.")));
    5589           0 :             break;
    5590             : 
    5591          14 :         case DB_IN_ARCHIVE_RECOVERY:
    5592          14 :             ereport(LOG,
    5593             :                     (errmsg("database system was interrupted while in recovery at log time %s",
    5594             :                             str_time(ControlFile->checkPointCopy.time,
    5595             :                                      timebuf, sizeof(timebuf))),
    5596             :                      errhint("If this has occurred more than once some data might be corrupted"
    5597             :                              " and you might need to choose an earlier recovery target.")));
    5598          14 :             break;
    5599             : 
    5600         354 :         case DB_IN_PRODUCTION:
    5601         354 :             ereport(LOG,
    5602             :                     (errmsg("database system was interrupted; last known up at %s",
    5603             :                             str_time(ControlFile->time,
    5604             :                                      timebuf, sizeof(timebuf)))));
    5605         354 :             break;
    5606             : 
    5607           0 :         default:
    5608           0 :             ereport(FATAL,
    5609             :                     (errcode(ERRCODE_DATA_CORRUPTED),
    5610             :                      errmsg("control file contains invalid database cluster state")));
    5611             :     }
    5612             : 
    5613             :     /* This is just to allow attaching to startup process with a debugger */
    5614             : #ifdef XLOG_REPLAY_DELAY
    5615             :     if (ControlFile->state != DB_SHUTDOWNED)
    5616             :         pg_usleep(60000000L);
    5617             : #endif
    5618             : 
    5619             :     /*
    5620             :      * Verify that pg_wal, pg_wal/archive_status, and pg_wal/summaries exist.
    5621             :      * In cases where someone has performed a copy for PITR, these directories
    5622             :      * may have been excluded and need to be re-created.
    5623             :      */
    5624        1982 :     ValidateXLOGDirectoryStructure();
    5625             : 
    5626             :     /* Set up timeout handler needed to report startup progress. */
    5627        1982 :     if (!IsBootstrapProcessingMode())
    5628        1880 :         RegisterTimeout(STARTUP_PROGRESS_TIMEOUT,
    5629             :                         startup_progress_timeout_handler);
    5630             : 
    5631             :     /*----------
    5632             :      * If we previously crashed, perform a couple of actions:
    5633             :      *
    5634             :      * - The pg_wal directory may still include some temporary WAL segments
    5635             :      *   used when creating a new segment, so perform some clean up to not
    5636             :      *   bloat this path.  This is done first as there is no point to sync
    5637             :      *   this temporary data.
    5638             :      *
    5639             :      * - There might be data which we had written, intending to fsync it, but
    5640             :      *   which we had not actually fsync'd yet.  Therefore, a power failure in
    5641             :      *   the near future might cause earlier unflushed writes to be lost, even
    5642             :      *   though more recent data written to disk from here on would be
    5643             :      *   persisted.  To avoid that, fsync the entire data directory.
    5644             :      */
    5645        1982 :     if (ControlFile->state != DB_SHUTDOWNED &&
    5646         434 :         ControlFile->state != DB_SHUTDOWNED_IN_RECOVERY)
    5647             :     {
    5648         368 :         RemoveTempXlogFiles();
    5649         368 :         SyncDataDirectory();
    5650         368 :         didCrash = true;
    5651             :     }
    5652             :     else
    5653        1614 :         didCrash = false;
    5654             : 
    5655             :     /*
    5656             :      * Prepare for WAL recovery if needed.
    5657             :      *
    5658             :      * InitWalRecovery analyzes the control file and the backup label file, if
    5659             :      * any.  It updates the in-memory ControlFile buffer according to the
    5660             :      * starting checkpoint, and sets InRecovery and ArchiveRecoveryRequested.
    5661             :      * It also applies the tablespace map file, if any.
    5662             :      */
    5663        1982 :     InitWalRecovery(ControlFile, &wasShutdown,
    5664             :                     &haveBackupLabel, &haveTblspcMap);
    5665        1980 :     checkPoint = ControlFile->checkPointCopy;
    5666             : 
    5667             :     /* initialize shared memory variables from the checkpoint record */
    5668        1980 :     TransamVariables->nextXid = checkPoint.nextXid;
    5669        1980 :     TransamVariables->nextOid = checkPoint.nextOid;
    5670        1980 :     TransamVariables->oidCount = 0;
    5671        1980 :     MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset);
    5672        1980 :     AdvanceOldestClogXid(checkPoint.oldestXid);
    5673        1980 :     SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
    5674        1980 :     SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB);
    5675        1980 :     SetCommitTsLimit(checkPoint.oldestCommitTsXid,
    5676             :                      checkPoint.newestCommitTsXid);
    5677             : 
    5678             :     /*
    5679             :      * Clear out any old relcache cache files.  This is *necessary* if we do
    5680             :      * any WAL replay, since that would probably result in the cache files
    5681             :      * being out of sync with database reality.  In theory we could leave them
    5682             :      * in place if the database had been cleanly shut down, but it seems
    5683             :      * safest to just remove them always and let them be rebuilt during the
    5684             :      * first backend startup.  These files needs to be removed from all
    5685             :      * directories including pg_tblspc, however the symlinks are created only
    5686             :      * after reading tablespace_map file in case of archive recovery from
    5687             :      * backup, so needs to clear old relcache files here after creating
    5688             :      * symlinks.
    5689             :      */
    5690        1980 :     RelationCacheInitFileRemove();
    5691             : 
    5692             :     /*
    5693             :      * Initialize replication slots, before there's a chance to remove
    5694             :      * required resources.
    5695             :      */
    5696        1980 :     StartupReplicationSlots();
    5697             : 
    5698             :     /*
    5699             :      * Startup the logical decoding status with the last status stored in the
    5700             :      * checkpoint record.
    5701             :      */
    5702        1976 :     StartupLogicalDecodingStatus(checkPoint.logicalDecodingEnabled);
    5703             : 
    5704             :     /*
    5705             :      * Startup logical state, needs to be setup now so we have proper data
    5706             :      * during crash recovery.
    5707             :      */
    5708        1976 :     StartupReorderBuffer();
    5709             : 
    5710             :     /*
    5711             :      * Startup CLOG. This must be done after TransamVariables->nextXid has
    5712             :      * been initialized and before we accept connections or begin WAL replay.
    5713             :      */
    5714        1976 :     StartupCLOG();
    5715             : 
    5716             :     /*
    5717             :      * Startup MultiXact. We need to do this early to be able to replay
    5718             :      * truncations.
    5719             :      */
    5720        1976 :     StartupMultiXact();
    5721             : 
    5722             :     /*
    5723             :      * Ditto for commit timestamps.  Activate the facility if the setting is
    5724             :      * enabled in the control file, as there should be no tracking of commit
    5725             :      * timestamps done when the setting was disabled.  This facility can be
    5726             :      * started or stopped when replaying a XLOG_PARAMETER_CHANGE record.
    5727             :      */
    5728        1976 :     if (ControlFile->track_commit_timestamp)
    5729          28 :         StartupCommitTs();
    5730             : 
    5731             :     /*
    5732             :      * Recover knowledge about replay progress of known replication partners.
    5733             :      */
    5734        1976 :     StartupReplicationOrigin();
    5735             : 
    5736             :     /*
    5737             :      * Initialize unlogged LSN. On a clean shutdown, it's restored from the
    5738             :      * control file. On recovery, all unlogged relations are blown away, so
    5739             :      * the unlogged LSN counter can be reset too.
    5740             :      */
    5741        1976 :     if (ControlFile->state == DB_SHUTDOWNED)
    5742        1532 :         pg_atomic_write_membarrier_u64(&XLogCtl->unloggedLSN,
    5743        1532 :                                        ControlFile->unloggedLSN);
    5744             :     else
    5745         444 :         pg_atomic_write_membarrier_u64(&XLogCtl->unloggedLSN,
    5746             :                                        FirstNormalUnloggedLSN);
    5747             : 
    5748             :     /*
    5749             :      * Copy any missing timeline history files between 'now' and the recovery
    5750             :      * target timeline from archive to pg_wal. While we don't need those files
    5751             :      * ourselves - the history file of the recovery target timeline covers all
    5752             :      * the previous timelines in the history too - a cascading standby server
    5753             :      * might be interested in them. Or, if you archive the WAL from this
    5754             :      * server to a different archive than the primary, it'd be good for all
    5755             :      * the history files to get archived there after failover, so that you can
    5756             :      * use one of the old timelines as a PITR target. Timeline history files
    5757             :      * are small, so it's better to copy them unnecessarily than not copy them
    5758             :      * and regret later.
    5759             :      */
    5760        1976 :     restoreTimeLineHistoryFiles(checkPoint.ThisTimeLineID, recoveryTargetTLI);
    5761             : 
    5762             :     /*
    5763             :      * Before running in recovery, scan pg_twophase and fill in its status to
    5764             :      * be able to work on entries generated by redo.  Doing a scan before
    5765             :      * taking any recovery action has the merit to discard any 2PC files that
    5766             :      * are newer than the first record to replay, saving from any conflicts at
    5767             :      * replay.  This avoids as well any subsequent scans when doing recovery
    5768             :      * of the on-disk two-phase data.
    5769             :      */
    5770        1976 :     restoreTwoPhaseData();
    5771             : 
    5772             :     /*
    5773             :      * When starting with crash recovery, reset pgstat data - it might not be
    5774             :      * valid. Otherwise restore pgstat data. It's safe to do this here,
    5775             :      * because postmaster will not yet have started any other processes.
    5776             :      *
    5777             :      * NB: Restoring replication slot stats relies on slot state to have
    5778             :      * already been restored from disk.
    5779             :      *
    5780             :      * TODO: With a bit of extra work we could just start with a pgstat file
    5781             :      * associated with the checkpoint redo location we're starting from.
    5782             :      */
    5783        1976 :     if (didCrash)
    5784         366 :         pgstat_discard_stats();
    5785             :     else
    5786        1610 :         pgstat_restore_stats();
    5787             : 
    5788        1976 :     lastFullPageWrites = checkPoint.fullPageWrites;
    5789             : 
    5790        1976 :     RedoRecPtr = XLogCtl->RedoRecPtr = XLogCtl->Insert.RedoRecPtr = checkPoint.redo;
    5791        1976 :     doPageWrites = lastFullPageWrites;
    5792             : 
    5793             :     /* REDO */
    5794        1976 :     if (InRecovery)
    5795             :     {
    5796             :         /* Initialize state for RecoveryInProgress() */
    5797         444 :         SpinLockAcquire(&XLogCtl->info_lck);
    5798         444 :         if (InArchiveRecovery)
    5799         238 :             XLogCtl->SharedRecoveryState = RECOVERY_STATE_ARCHIVE;
    5800             :         else
    5801         206 :             XLogCtl->SharedRecoveryState = RECOVERY_STATE_CRASH;
    5802         444 :         SpinLockRelease(&XLogCtl->info_lck);
    5803             : 
    5804             :         /*
    5805             :          * Update pg_control to show that we are recovering and to show the
    5806             :          * selected checkpoint as the place we are starting from. We also mark
    5807             :          * pg_control with any minimum recovery stop point obtained from a
    5808             :          * backup history file.
    5809             :          *
    5810             :          * No need to hold ControlFileLock yet, we aren't up far enough.
    5811             :          */
    5812         444 :         UpdateControlFile();
    5813             : 
    5814             :         /*
    5815             :          * If there was a backup label file, it's done its job and the info
    5816             :          * has now been propagated into pg_control.  We must get rid of the
    5817             :          * label file so that if we crash during recovery, we'll pick up at
    5818             :          * the latest recovery restartpoint instead of going all the way back
    5819             :          * to the backup start point.  It seems prudent though to just rename
    5820             :          * the file out of the way rather than delete it completely.
    5821             :          */
    5822         444 :         if (haveBackupLabel)
    5823             :         {
    5824         156 :             unlink(BACKUP_LABEL_OLD);
    5825         156 :             durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, FATAL);
    5826             :         }
    5827             : 
    5828             :         /*
    5829             :          * If there was a tablespace_map file, it's done its job and the
    5830             :          * symlinks have been created.  We must get rid of the map file so
    5831             :          * that if we crash during recovery, we don't create symlinks again.
    5832             :          * It seems prudent though to just rename the file out of the way
    5833             :          * rather than delete it completely.
    5834             :          */
    5835         444 :         if (haveTblspcMap)
    5836             :         {
    5837           4 :             unlink(TABLESPACE_MAP_OLD);
    5838           4 :             durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, FATAL);
    5839             :         }
    5840             : 
    5841             :         /*
    5842             :          * Initialize our local copy of minRecoveryPoint.  When doing crash
    5843             :          * recovery we want to replay up to the end of WAL.  Particularly, in
    5844             :          * the case of a promoted standby minRecoveryPoint value in the
    5845             :          * control file is only updated after the first checkpoint.  However,
    5846             :          * if the instance crashes before the first post-recovery checkpoint
    5847             :          * is completed then recovery will use a stale location causing the
    5848             :          * startup process to think that there are still invalid page
    5849             :          * references when checking for data consistency.
    5850             :          */
    5851         444 :         if (InArchiveRecovery)
    5852             :         {
    5853         238 :             LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
    5854         238 :             LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
    5855             :         }
    5856             :         else
    5857             :         {
    5858         206 :             LocalMinRecoveryPoint = InvalidXLogRecPtr;
    5859         206 :             LocalMinRecoveryPointTLI = 0;
    5860             :         }
    5861             : 
    5862             :         /* Check that the GUCs used to generate the WAL allow recovery */
    5863         444 :         CheckRequiredParameterValues();
    5864             : 
    5865             :         /*
    5866             :          * We're in recovery, so unlogged relations may be trashed and must be
    5867             :          * reset.  This should be done BEFORE allowing Hot Standby
    5868             :          * connections, so that read-only backends don't try to read whatever
    5869             :          * garbage is left over from before.
    5870             :          */
    5871         444 :         ResetUnloggedRelations(UNLOGGED_RELATION_CLEANUP);
    5872             : 
    5873             :         /*
    5874             :          * Likewise, delete any saved transaction snapshot files that got left
    5875             :          * behind by crashed backends.
    5876             :          */
    5877         444 :         DeleteAllExportedSnapshotFiles();
    5878             : 
    5879             :         /*
    5880             :          * Initialize for Hot Standby, if enabled. We won't let backends in
    5881             :          * yet, not until we've reached the min recovery point specified in
    5882             :          * control file and we've established a recovery snapshot from a
    5883             :          * running-xacts WAL record.
    5884             :          */
    5885         444 :         if (ArchiveRecoveryRequested && EnableHotStandby)
    5886             :         {
    5887             :             TransactionId *xids;
    5888             :             int         nxids;
    5889             : 
    5890         226 :             ereport(DEBUG1,
    5891             :                     (errmsg_internal("initializing for hot standby")));
    5892             : 
    5893         226 :             InitRecoveryTransactionEnvironment();
    5894             : 
    5895         226 :             if (wasShutdown)
    5896          52 :                 oldestActiveXID = PrescanPreparedTransactions(&xids, &nxids);
    5897             :             else
    5898         174 :                 oldestActiveXID = checkPoint.oldestActiveXid;
    5899             :             Assert(TransactionIdIsValid(oldestActiveXID));
    5900             : 
    5901             :             /* Tell procarray about the range of xids it has to deal with */
    5902         226 :             ProcArrayInitRecovery(XidFromFullTransactionId(TransamVariables->nextXid));
    5903             : 
    5904             :             /*
    5905             :              * Startup subtrans only.  CLOG, MultiXact and commit timestamp
    5906             :              * have already been started up and other SLRUs are not maintained
    5907             :              * during recovery and need not be started yet.
    5908             :              */
    5909         226 :             StartupSUBTRANS(oldestActiveXID);
    5910             : 
    5911             :             /*
    5912             :              * If we're beginning at a shutdown checkpoint, we know that
    5913             :              * nothing was running on the primary at this point. So fake-up an
    5914             :              * empty running-xacts record and use that here and now. Recover
    5915             :              * additional standby state for prepared transactions.
    5916             :              */
    5917         226 :             if (wasShutdown)
    5918             :             {
    5919             :                 RunningTransactionsData running;
    5920             :                 TransactionId latestCompletedXid;
    5921             : 
    5922             :                 /* Update pg_subtrans entries for any prepared transactions */
    5923          52 :                 StandbyRecoverPreparedTransactions();
    5924             : 
    5925             :                 /*
    5926             :                  * Construct a RunningTransactions snapshot representing a
    5927             :                  * shut down server, with only prepared transactions still
    5928             :                  * alive. We're never overflowed at this point because all
    5929             :                  * subxids are listed with their parent prepared transactions.
    5930             :                  */
    5931          52 :                 running.xcnt = nxids;
    5932          52 :                 running.subxcnt = 0;
    5933          52 :                 running.subxid_status = SUBXIDS_IN_SUBTRANS;
    5934          52 :                 running.nextXid = XidFromFullTransactionId(checkPoint.nextXid);
    5935          52 :                 running.oldestRunningXid = oldestActiveXID;
    5936          52 :                 latestCompletedXid = XidFromFullTransactionId(checkPoint.nextXid);
    5937          52 :                 TransactionIdRetreat(latestCompletedXid);
    5938             :                 Assert(TransactionIdIsNormal(latestCompletedXid));
    5939          52 :                 running.latestCompletedXid = latestCompletedXid;
    5940          52 :                 running.xids = xids;
    5941             : 
    5942          52 :                 ProcArrayApplyRecoveryInfo(&running);
    5943             :             }
    5944             :         }
    5945             : 
    5946             :         /*
    5947             :          * We're all set for replaying the WAL now. Do it.
    5948             :          */
    5949         444 :         PerformWalRecovery();
    5950         324 :         performedWalRecovery = true;
    5951             :     }
    5952             :     else
    5953        1532 :         performedWalRecovery = false;
    5954             : 
    5955             :     /*
    5956             :      * Finish WAL recovery.
    5957             :      */
    5958        1856 :     endOfRecoveryInfo = FinishWalRecovery();
    5959        1856 :     EndOfLog = endOfRecoveryInfo->endOfLog;
    5960        1856 :     EndOfLogTLI = endOfRecoveryInfo->endOfLogTLI;
    5961        1856 :     abortedRecPtr = endOfRecoveryInfo->abortedRecPtr;
    5962        1856 :     missingContrecPtr = endOfRecoveryInfo->missingContrecPtr;
    5963             : 
    5964             :     /*
    5965             :      * Reset ps status display, so as no information related to recovery shows
    5966             :      * up.
    5967             :      */
    5968        1856 :     set_ps_display("");
    5969             : 
    5970             :     /*
    5971             :      * When recovering from a backup (we are in recovery, and archive recovery
    5972             :      * was requested), complain if we did not roll forward far enough to reach
    5973             :      * the point where the database is consistent.  For regular online
    5974             :      * backup-from-primary, that means reaching the end-of-backup WAL record
    5975             :      * (at which point we reset backupStartPoint to be Invalid), for
    5976             :      * backup-from-replica (which can't inject records into the WAL stream),
    5977             :      * that point is when we reach the minRecoveryPoint in pg_control (which
    5978             :      * we purposefully copy last when backing up from a replica).  For
    5979             :      * pg_rewind (which creates a backup_label with a method of "pg_rewind")
    5980             :      * or snapshot-style backups (which don't), backupEndRequired will be set
    5981             :      * to false.
    5982             :      *
    5983             :      * Note: it is indeed okay to look at the local variable
    5984             :      * LocalMinRecoveryPoint here, even though ControlFile->minRecoveryPoint
    5985             :      * might be further ahead --- ControlFile->minRecoveryPoint cannot have
    5986             :      * been advanced beyond the WAL we processed.
    5987             :      */
    5988        1856 :     if (InRecovery &&
    5989         324 :         (EndOfLog < LocalMinRecoveryPoint ||
    5990         324 :          XLogRecPtrIsValid(ControlFile->backupStartPoint)))
    5991             :     {
    5992             :         /*
    5993             :          * Ran off end of WAL before reaching end-of-backup WAL record, or
    5994             :          * minRecoveryPoint. That's a bad sign, indicating that you tried to
    5995             :          * recover from an online backup but never called pg_backup_stop(), or
    5996             :          * you didn't archive all the WAL needed.
    5997             :          */
    5998           0 :         if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
    5999             :         {
    6000           0 :             if (XLogRecPtrIsValid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
    6001           0 :                 ereport(FATAL,
    6002             :                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    6003             :                          errmsg("WAL ends before end of online backup"),
    6004             :                          errhint("All WAL generated while online backup was taken must be available at recovery.")));
    6005             :             else
    6006           0 :                 ereport(FATAL,
    6007             :                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    6008             :                          errmsg("WAL ends before consistent recovery point")));
    6009             :         }
    6010             :     }
    6011             : 
    6012             :     /*
    6013             :      * Reset unlogged relations to the contents of their INIT fork. This is
    6014             :      * done AFTER recovery is complete so as to include any unlogged relations
    6015             :      * created during recovery, but BEFORE recovery is marked as having
    6016             :      * completed successfully. Otherwise we'd not retry if any of the post
    6017             :      * end-of-recovery steps fail.
    6018             :      */
    6019        1856 :     if (InRecovery)
    6020         324 :         ResetUnloggedRelations(UNLOGGED_RELATION_INIT);
    6021             : 
    6022             :     /*
    6023             :      * Pre-scan prepared transactions to find out the range of XIDs present.
    6024             :      * This information is not quite needed yet, but it is positioned here so
    6025             :      * as potential problems are detected before any on-disk change is done.
    6026             :      */
    6027        1856 :     oldestActiveXID = PrescanPreparedTransactions(NULL, NULL);
    6028             : 
    6029             :     /*
    6030             :      * Allow ordinary WAL segment creation before possibly switching to a new
    6031             :      * timeline, which creates a new segment, and after the last ReadRecord().
    6032             :      */
    6033        1856 :     SetInstallXLogFileSegmentActive();
    6034             : 
    6035             :     /*
    6036             :      * Consider whether we need to assign a new timeline ID.
    6037             :      *
    6038             :      * If we did archive recovery, we always assign a new ID.  This handles a
    6039             :      * couple of issues.  If we stopped short of the end of WAL during
    6040             :      * recovery, then we are clearly generating a new timeline and must assign
    6041             :      * it a unique new ID.  Even if we ran to the end, modifying the current
    6042             :      * last segment is problematic because it may result in trying to
    6043             :      * overwrite an already-archived copy of that segment, and we encourage
    6044             :      * DBAs to make their archive_commands reject that.  We can dodge the
    6045             :      * problem by making the new active segment have a new timeline ID.
    6046             :      *
    6047             :      * In a normal crash recovery, we can just extend the timeline we were in.
    6048             :      */
    6049        1856 :     newTLI = endOfRecoveryInfo->lastRecTLI;
    6050        1856 :     if (ArchiveRecoveryRequested)
    6051             :     {
    6052         110 :         newTLI = findNewestTimeLine(recoveryTargetTLI) + 1;
    6053         110 :         ereport(LOG,
    6054             :                 (errmsg("selected new timeline ID: %u", newTLI)));
    6055             : 
    6056             :         /*
    6057             :          * Make a writable copy of the last WAL segment.  (Note that we also
    6058             :          * have a copy of the last block of the old WAL in
    6059             :          * endOfRecovery->lastPage; we will use that below.)
    6060             :          */
    6061         110 :         XLogInitNewTimeline(EndOfLogTLI, EndOfLog, newTLI);
    6062             : 
    6063             :         /*
    6064             :          * Remove the signal files out of the way, so that we don't
    6065             :          * accidentally re-enter archive recovery mode in a subsequent crash.
    6066             :          */
    6067         110 :         if (endOfRecoveryInfo->standby_signal_file_found)
    6068         104 :             durable_unlink(STANDBY_SIGNAL_FILE, FATAL);
    6069             : 
    6070         110 :         if (endOfRecoveryInfo->recovery_signal_file_found)
    6071           6 :             durable_unlink(RECOVERY_SIGNAL_FILE, FATAL);
    6072             : 
    6073             :         /*
    6074             :          * Write the timeline history file, and have it archived. After this
    6075             :          * point (or rather, as soon as the file is archived), the timeline
    6076             :          * will appear as "taken" in the WAL archive and to any standby
    6077             :          * servers.  If we crash before actually switching to the new
    6078             :          * timeline, standby servers will nevertheless think that we switched
    6079             :          * to the new timeline, and will try to connect to the new timeline.
    6080             :          * To minimize the window for that, try to do as little as possible
    6081             :          * between here and writing the end-of-recovery record.
    6082             :          */
    6083         110 :         writeTimeLineHistory(newTLI, recoveryTargetTLI,
    6084             :                              EndOfLog, endOfRecoveryInfo->recoveryStopReason);
    6085             : 
    6086         110 :         ereport(LOG,
    6087             :                 (errmsg("archive recovery complete")));
    6088             :     }
    6089             : 
    6090             :     /* Save the selected TimeLineID in shared memory, too */
    6091        1856 :     SpinLockAcquire(&XLogCtl->info_lck);
    6092        1856 :     XLogCtl->InsertTimeLineID = newTLI;
    6093        1856 :     XLogCtl->PrevTimeLineID = endOfRecoveryInfo->lastRecTLI;
    6094        1856 :     SpinLockRelease(&XLogCtl->info_lck);
    6095             : 
    6096             :     /*
    6097             :      * Actually, if WAL ended in an incomplete record, skip the parts that
    6098             :      * made it through and start writing after the portion that persisted.
    6099             :      * (It's critical to first write an OVERWRITE_CONTRECORD message, which
    6100             :      * we'll do as soon as we're open for writing new WAL.)
    6101             :      */
    6102        1856 :     if (XLogRecPtrIsValid(missingContrecPtr))
    6103             :     {
    6104             :         /*
    6105             :          * We should only have a missingContrecPtr if we're not switching to a
    6106             :          * new timeline. When a timeline switch occurs, WAL is copied from the
    6107             :          * old timeline to the new only up to the end of the last complete
    6108             :          * record, so there can't be an incomplete WAL record that we need to
    6109             :          * disregard.
    6110             :          */
    6111             :         Assert(newTLI == endOfRecoveryInfo->lastRecTLI);
    6112             :         Assert(XLogRecPtrIsValid(abortedRecPtr));
    6113          22 :         EndOfLog = missingContrecPtr;
    6114             :     }
    6115             : 
    6116             :     /*
    6117             :      * Prepare to write WAL starting at EndOfLog location, and init xlog
    6118             :      * buffer cache using the block containing the last record from the
    6119             :      * previous incarnation.
    6120             :      */
    6121        1856 :     Insert = &XLogCtl->Insert;
    6122        1856 :     Insert->PrevBytePos = XLogRecPtrToBytePos(endOfRecoveryInfo->lastRec);
    6123        1856 :     Insert->CurrBytePos = XLogRecPtrToBytePos(EndOfLog);
    6124             : 
    6125             :     /*
    6126             :      * Tricky point here: lastPage contains the *last* block that the LastRec
    6127             :      * record spans, not the one it starts in.  The last block is indeed the
    6128             :      * one we want to use.
    6129             :      */
    6130        1856 :     if (EndOfLog % XLOG_BLCKSZ != 0)
    6131             :     {
    6132             :         char       *page;
    6133             :         int         len;
    6134             :         int         firstIdx;
    6135             : 
    6136        1800 :         firstIdx = XLogRecPtrToBufIdx(EndOfLog);
    6137        1800 :         len = EndOfLog - endOfRecoveryInfo->lastPageBeginPtr;
    6138             :         Assert(len < XLOG_BLCKSZ);
    6139             : 
    6140             :         /* Copy the valid part of the last block, and zero the rest */
    6141        1800 :         page = &XLogCtl->pages[firstIdx * XLOG_BLCKSZ];
    6142        1800 :         memcpy(page, endOfRecoveryInfo->lastPage, len);
    6143        1800 :         memset(page + len, 0, XLOG_BLCKSZ - len);
    6144             : 
    6145        1800 :         pg_atomic_write_u64(&XLogCtl->xlblocks[firstIdx], endOfRecoveryInfo->lastPageBeginPtr + XLOG_BLCKSZ);
    6146        1800 :         XLogCtl->InitializedUpTo = endOfRecoveryInfo->lastPageBeginPtr + XLOG_BLCKSZ;
    6147             :     }
    6148             :     else
    6149             :     {
    6150             :         /*
    6151             :          * There is no partial block to copy. Just set InitializedUpTo, and
    6152             :          * let the first attempt to insert a log record to initialize the next
    6153             :          * buffer.
    6154             :          */
    6155          56 :         XLogCtl->InitializedUpTo = EndOfLog;
    6156             :     }
    6157             : 
    6158             :     /*
    6159             :      * Update local and shared status.  This is OK to do without any locks
    6160             :      * because no other process can be reading or writing WAL yet.
    6161             :      */
    6162        1856 :     LogwrtResult.Write = LogwrtResult.Flush = EndOfLog;
    6163        1856 :     pg_atomic_write_u64(&XLogCtl->logInsertResult, EndOfLog);
    6164        1856 :     pg_atomic_write_u64(&XLogCtl->logWriteResult, EndOfLog);
    6165        1856 :     pg_atomic_write_u64(&XLogCtl->logFlushResult, EndOfLog);
    6166        1856 :     XLogCtl->LogwrtRqst.Write = EndOfLog;
    6167        1856 :     XLogCtl->LogwrtRqst.Flush = EndOfLog;
    6168             : 
    6169             :     /*
    6170             :      * Preallocate additional log files, if wanted.
    6171             :      */
    6172        1856 :     PreallocXlogFiles(EndOfLog, newTLI);
    6173             : 
    6174             :     /*
    6175             :      * Okay, we're officially UP.
    6176             :      */
    6177        1856 :     InRecovery = false;
    6178             : 
    6179             :     /* start the archive_timeout timer and LSN running */
    6180        1856 :     XLogCtl->lastSegSwitchTime = (pg_time_t) time(NULL);
    6181        1856 :     XLogCtl->lastSegSwitchLSN = EndOfLog;
    6182             : 
    6183             :     /* also initialize latestCompletedXid, to nextXid - 1 */
    6184        1856 :     LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
    6185        1856 :     TransamVariables->latestCompletedXid = TransamVariables->nextXid;
    6186        1856 :     FullTransactionIdRetreat(&TransamVariables->latestCompletedXid);
    6187        1856 :     LWLockRelease(ProcArrayLock);
    6188             : 
    6189             :     /*
    6190             :      * Start up subtrans, if not already done for hot standby.  (commit
    6191             :      * timestamps are started below, if necessary.)
    6192             :      */
    6193        1856 :     if (standbyState == STANDBY_DISABLED)
    6194        1746 :         StartupSUBTRANS(oldestActiveXID);
    6195             : 
    6196             :     /*
    6197             :      * Perform end of recovery actions for any SLRUs that need it.
    6198             :      */
    6199        1856 :     TrimCLOG();
    6200        1856 :     TrimMultiXact();
    6201             : 
    6202             :     /*
    6203             :      * Reload shared-memory state for prepared transactions.  This needs to
    6204             :      * happen before renaming the last partial segment of the old timeline as
    6205             :      * it may be possible that we have to recover some transactions from it.
    6206             :      */
    6207        1856 :     RecoverPreparedTransactions();
    6208             : 
    6209             :     /* Shut down xlogreader */
    6210        1856 :     ShutdownWalRecovery();
    6211             : 
    6212             :     /* Enable WAL writes for this backend only. */
    6213        1856 :     LocalSetXLogInsertAllowed();
    6214             : 
    6215             :     /* If necessary, write overwrite-contrecord before doing anything else */
    6216        1856 :     if (XLogRecPtrIsValid(abortedRecPtr))
    6217             :     {
    6218             :         Assert(XLogRecPtrIsValid(missingContrecPtr));
    6219          22 :         CreateOverwriteContrecordRecord(abortedRecPtr, missingContrecPtr, newTLI);
    6220             :     }
    6221             : 
    6222             :     /*
    6223             :      * Update full_page_writes in shared memory and write an XLOG_FPW_CHANGE
    6224             :      * record before resource manager writes cleanup WAL records or checkpoint
    6225             :      * record is written.
    6226             :      */
    6227        1856 :     Insert->fullPageWrites = lastFullPageWrites;
    6228        1856 :     UpdateFullPageWrites();
    6229             : 
    6230             :     /*
    6231             :      * Emit checkpoint or end-of-recovery record in XLOG, if required.
    6232             :      */
    6233        1856 :     if (performedWalRecovery)
    6234         324 :         promoted = PerformRecoveryXLogAction();
    6235             : 
    6236             :     /*
    6237             :      * If any of the critical GUCs have changed, log them before we allow
    6238             :      * backends to write WAL.
    6239             :      */
    6240        1856 :     XLogReportParameters();
    6241             : 
    6242             :     /* If this is archive recovery, perform post-recovery cleanup actions. */
    6243        1856 :     if (ArchiveRecoveryRequested)
    6244         110 :         CleanupAfterArchiveRecovery(EndOfLogTLI, EndOfLog, newTLI);
    6245             : 
    6246             :     /*
    6247             :      * Local WAL inserts enabled, so it's time to finish initialization of
    6248             :      * commit timestamp.
    6249             :      */
    6250        1856 :     CompleteCommitTsInitialization();
    6251             : 
    6252             :     /*
    6253             :      * Update logical decoding status in shared memory and write an
    6254             :      * XLOG_LOGICAL_DECODING_STATUS_CHANGE, if necessary.
    6255             :      */
    6256        1856 :     UpdateLogicalDecodingStatusEndOfRecovery();
    6257             : 
    6258             :     /* Clean up EndOfWalRecoveryInfo data to appease Valgrind leak checking */
    6259        1856 :     if (endOfRecoveryInfo->lastPage)
    6260        1822 :         pfree(endOfRecoveryInfo->lastPage);
    6261        1856 :     pfree(endOfRecoveryInfo->recoveryStopReason);
    6262        1856 :     pfree(endOfRecoveryInfo);
    6263             : 
    6264             :     /*
    6265             :      * All done with end-of-recovery actions.
    6266             :      *
    6267             :      * Now allow backends to write WAL and update the control file status in
    6268             :      * consequence.  SharedRecoveryState, that controls if backends can write
    6269             :      * WAL, is updated while holding ControlFileLock to prevent other backends
    6270             :      * to look at an inconsistent state of the control file in shared memory.
    6271             :      * There is still a small window during which backends can write WAL and
    6272             :      * the control file is still referring to a system not in DB_IN_PRODUCTION
    6273             :      * state while looking at the on-disk control file.
    6274             :      *
    6275             :      * Also, we use info_lck to update SharedRecoveryState to ensure that
    6276             :      * there are no race conditions concerning visibility of other recent
    6277             :      * updates to shared memory.
    6278             :      */
    6279        1856 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    6280        1856 :     ControlFile->state = DB_IN_PRODUCTION;
    6281             : 
    6282        1856 :     SpinLockAcquire(&XLogCtl->info_lck);
    6283        1856 :     XLogCtl->SharedRecoveryState = RECOVERY_STATE_DONE;
    6284        1856 :     SpinLockRelease(&XLogCtl->info_lck);
    6285             : 
    6286        1856 :     UpdateControlFile();
    6287        1856 :     LWLockRelease(ControlFileLock);
    6288             : 
    6289             :     /*
    6290             :      * Wake up the checkpointer process as there might be a request to disable
    6291             :      * logical decoding by concurrent slot drop.
    6292             :      */
    6293        1856 :     WakeupCheckpointer();
    6294             : 
    6295             :     /*
    6296             :      * Wake up all waiters.  They need to report an error that recovery was
    6297             :      * ended before reaching the target LSN.
    6298             :      */
    6299        1856 :     WaitLSNWakeup(WAIT_LSN_TYPE_STANDBY_REPLAY, InvalidXLogRecPtr);
    6300        1856 :     WaitLSNWakeup(WAIT_LSN_TYPE_STANDBY_WRITE, InvalidXLogRecPtr);
    6301        1856 :     WaitLSNWakeup(WAIT_LSN_TYPE_STANDBY_FLUSH, InvalidXLogRecPtr);
    6302             : 
    6303             :     /*
    6304             :      * Shutdown the recovery environment.  This must occur after
    6305             :      * RecoverPreparedTransactions() (see notes in lock_twophase_recover())
    6306             :      * and after switching SharedRecoveryState to RECOVERY_STATE_DONE so as
    6307             :      * any session building a snapshot will not rely on KnownAssignedXids as
    6308             :      * RecoveryInProgress() would return false at this stage.  This is
    6309             :      * particularly critical for prepared 2PC transactions, that would still
    6310             :      * need to be included in snapshots once recovery has ended.
    6311             :      */
    6312        1856 :     if (standbyState != STANDBY_DISABLED)
    6313         110 :         ShutdownRecoveryTransactionEnvironment();
    6314             : 
    6315             :     /*
    6316             :      * If there were cascading standby servers connected to us, nudge any wal
    6317             :      * sender processes to notice that we've been promoted.
    6318             :      */
    6319        1856 :     WalSndWakeup(true, true);
    6320             : 
    6321             :     /*
    6322             :      * If this was a promotion, request an (online) checkpoint now. This isn't
    6323             :      * required for consistency, but the last restartpoint might be far back,
    6324             :      * and in case of a crash, recovering from it might take a longer than is
    6325             :      * appropriate now that we're not in standby mode anymore.
    6326             :      */
    6327        1856 :     if (promoted)
    6328          96 :         RequestCheckpoint(CHECKPOINT_FORCE);
    6329        1856 : }
    6330             : 
    6331             : /*
    6332             :  * Callback from PerformWalRecovery(), called when we switch from crash
    6333             :  * recovery to archive recovery mode.  Updates the control file accordingly.
    6334             :  */
    6335             : void
    6336           4 : SwitchIntoArchiveRecovery(XLogRecPtr EndRecPtr, TimeLineID replayTLI)
    6337             : {
    6338             :     /* initialize minRecoveryPoint to this record */
    6339           4 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    6340           4 :     ControlFile->state = DB_IN_ARCHIVE_RECOVERY;
    6341           4 :     if (ControlFile->minRecoveryPoint < EndRecPtr)
    6342             :     {
    6343           4 :         ControlFile->minRecoveryPoint = EndRecPtr;
    6344           4 :         ControlFile->minRecoveryPointTLI = replayTLI;
    6345             :     }
    6346             :     /* update local copy */
    6347           4 :     LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
    6348           4 :     LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
    6349             : 
    6350             :     /*
    6351             :      * The startup process can update its local copy of minRecoveryPoint from
    6352             :      * this point.
    6353             :      */
    6354           4 :     updateMinRecoveryPoint = true;
    6355             : 
    6356           4 :     UpdateControlFile();
    6357             : 
    6358             :     /*
    6359             :      * We update SharedRecoveryState while holding the lock on ControlFileLock
    6360             :      * so both states are consistent in shared memory.
    6361             :      */
    6362           4 :     SpinLockAcquire(&XLogCtl->info_lck);
    6363           4 :     XLogCtl->SharedRecoveryState = RECOVERY_STATE_ARCHIVE;
    6364           4 :     SpinLockRelease(&XLogCtl->info_lck);
    6365             : 
    6366           4 :     LWLockRelease(ControlFileLock);
    6367           4 : }
    6368             : 
    6369             : /*
    6370             :  * Callback from PerformWalRecovery(), called when we reach the end of backup.
    6371             :  * Updates the control file accordingly.
    6372             :  */
    6373             : void
    6374         156 : ReachedEndOfBackup(XLogRecPtr EndRecPtr, TimeLineID tli)
    6375             : {
    6376             :     /*
    6377             :      * We have reached the end of base backup, as indicated by pg_control. The
    6378             :      * data on disk is now consistent (unless minRecoveryPoint is further
    6379             :      * ahead, which can happen if we crashed during previous recovery).  Reset
    6380             :      * backupStartPoint and backupEndPoint, and update minRecoveryPoint to
    6381             :      * make sure we don't allow starting up at an earlier point even if
    6382             :      * recovery is stopped and restarted soon after this.
    6383             :      */
    6384         156 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    6385             : 
    6386         156 :     if (ControlFile->minRecoveryPoint < EndRecPtr)
    6387             :     {
    6388         146 :         ControlFile->minRecoveryPoint = EndRecPtr;
    6389         146 :         ControlFile->minRecoveryPointTLI = tli;
    6390             :     }
    6391             : 
    6392         156 :     ControlFile->backupStartPoint = InvalidXLogRecPtr;
    6393         156 :     ControlFile->backupEndPoint = InvalidXLogRecPtr;
    6394         156 :     ControlFile->backupEndRequired = false;
    6395         156 :     UpdateControlFile();
    6396             : 
    6397         156 :     LWLockRelease(ControlFileLock);
    6398         156 : }
    6399             : 
    6400             : /*
    6401             :  * Perform whatever XLOG actions are necessary at end of REDO.
    6402             :  *
    6403             :  * The goal here is to make sure that we'll be able to recover properly if
    6404             :  * we crash again. If we choose to write a checkpoint, we'll write a shutdown
    6405             :  * checkpoint rather than an on-line one. This is not particularly critical,
    6406             :  * but since we may be assigning a new TLI, using a shutdown checkpoint allows
    6407             :  * us to have the rule that TLI only changes in shutdown checkpoints, which
    6408             :  * allows some extra error checking in xlog_redo.
    6409             :  */
    6410             : static bool
    6411         324 : PerformRecoveryXLogAction(void)
    6412             : {
    6413         324 :     bool        promoted = false;
    6414             : 
    6415             :     /*
    6416             :      * Perform a checkpoint to update all our recovery activity to disk.
    6417             :      *
    6418             :      * Note that we write a shutdown checkpoint rather than an on-line one.
    6419             :      * This is not particularly critical, but since we may be assigning a new
    6420             :      * TLI, using a shutdown checkpoint allows us to have the rule that TLI
    6421             :      * only changes in shutdown checkpoints, which allows some extra error
    6422             :      * checking in xlog_redo.
    6423             :      *
    6424             :      * In promotion, only create a lightweight end-of-recovery record instead
    6425             :      * of a full checkpoint. A checkpoint is requested later, after we're
    6426             :      * fully out of recovery mode and already accepting queries.
    6427             :      */
    6428         434 :     if (ArchiveRecoveryRequested && IsUnderPostmaster &&
    6429         110 :         PromoteIsTriggered())
    6430             :     {
    6431          96 :         promoted = true;
    6432             : 
    6433             :         /*
    6434             :          * Insert a special WAL record to mark the end of recovery, since we
    6435             :          * aren't doing a checkpoint. That means that the checkpointer process
    6436             :          * may likely be in the middle of a time-smoothed restartpoint and
    6437             :          * could continue to be for minutes after this.  That sounds strange,
    6438             :          * but the effect is roughly the same and it would be stranger to try
    6439             :          * to come out of the restartpoint and then checkpoint. We request a
    6440             :          * checkpoint later anyway, just for safety.
    6441             :          */
    6442          96 :         CreateEndOfRecoveryRecord();
    6443             :     }
    6444             :     else
    6445             :     {
    6446         228 :         RequestCheckpoint(CHECKPOINT_END_OF_RECOVERY |
    6447             :                           CHECKPOINT_FAST |
    6448             :                           CHECKPOINT_WAIT);
    6449             :     }
    6450             : 
    6451         324 :     return promoted;
    6452             : }
    6453             : 
    6454             : /*
    6455             :  * Is the system still in recovery?
    6456             :  *
    6457             :  * Unlike testing InRecovery, this works in any process that's connected to
    6458             :  * shared memory.
    6459             :  */
    6460             : bool
    6461   161018146 : RecoveryInProgress(void)
    6462             : {
    6463             :     /*
    6464             :      * We check shared state each time only until we leave recovery mode. We
    6465             :      * can't re-enter recovery, so there's no need to keep checking after the
    6466             :      * shared variable has once been seen false.
    6467             :      */
    6468   161018146 :     if (!LocalRecoveryInProgress)
    6469   156441786 :         return false;
    6470             :     else
    6471             :     {
    6472             :         /*
    6473             :          * use volatile pointer to make sure we make a fresh read of the
    6474             :          * shared variable.
    6475             :          */
    6476     4576360 :         volatile XLogCtlData *xlogctl = XLogCtl;
    6477             : 
    6478     4576360 :         LocalRecoveryInProgress = (xlogctl->SharedRecoveryState != RECOVERY_STATE_DONE);
    6479             : 
    6480             :         /*
    6481             :          * Note: We don't need a memory barrier when we're still in recovery.
    6482             :          * We might exit recovery immediately after return, so the caller
    6483             :          * can't rely on 'true' meaning that we're still in recovery anyway.
    6484             :          */
    6485             : 
    6486     4576360 :         return LocalRecoveryInProgress;
    6487             :     }
    6488             : }
    6489             : 
    6490             : /*
    6491             :  * Returns current recovery state from shared memory.
    6492             :  *
    6493             :  * This returned state is kept consistent with the contents of the control
    6494             :  * file.  See details about the possible values of RecoveryState in xlog.h.
    6495             :  */
    6496             : RecoveryState
    6497        6426 : GetRecoveryState(void)
    6498             : {
    6499             :     RecoveryState retval;
    6500             : 
    6501        6426 :     SpinLockAcquire(&XLogCtl->info_lck);
    6502        6426 :     retval = XLogCtl->SharedRecoveryState;
    6503        6426 :     SpinLockRelease(&XLogCtl->info_lck);
    6504             : 
    6505        6426 :     return retval;
    6506             : }
    6507             : 
    6508             : /*
    6509             :  * Is this process allowed to insert new WAL records?
    6510             :  *
    6511             :  * Ordinarily this is essentially equivalent to !RecoveryInProgress().
    6512             :  * But we also have provisions for forcing the result "true" or "false"
    6513             :  * within specific processes regardless of the global state.
    6514             :  */
    6515             : bool
    6516    81945318 : XLogInsertAllowed(void)
    6517             : {
    6518             :     /*
    6519             :      * If value is "unconditionally true" or "unconditionally false", just
    6520             :      * return it.  This provides the normal fast path once recovery is known
    6521             :      * done.
    6522             :      */
    6523    81945318 :     if (LocalXLogInsertAllowed >= 0)
    6524    80443884 :         return (bool) LocalXLogInsertAllowed;
    6525             : 
    6526             :     /*
    6527             :      * Else, must check to see if we're still in recovery.
    6528             :      */
    6529     1501434 :     if (RecoveryInProgress())
    6530     1481872 :         return false;
    6531             : 
    6532             :     /*
    6533             :      * On exit from recovery, reset to "unconditionally true", since there is
    6534             :      * no need to keep checking.
    6535             :      */
    6536       19562 :     LocalXLogInsertAllowed = 1;
    6537       19562 :     return true;
    6538             : }
    6539             : 
    6540             : /*
    6541             :  * Make XLogInsertAllowed() return true in the current process only.
    6542             :  *
    6543             :  * Note: it is allowed to switch LocalXLogInsertAllowed back to -1 later,
    6544             :  * and even call LocalSetXLogInsertAllowed() again after that.
    6545             :  *
    6546             :  * Returns the previous value of LocalXLogInsertAllowed.
    6547             :  */
    6548             : static int
    6549        1912 : LocalSetXLogInsertAllowed(void)
    6550             : {
    6551        1912 :     int         oldXLogAllowed = LocalXLogInsertAllowed;
    6552             : 
    6553        1912 :     LocalXLogInsertAllowed = 1;
    6554             : 
    6555        1912 :     return oldXLogAllowed;
    6556             : }
    6557             : 
    6558             : /*
    6559             :  * Return the current Redo pointer from shared memory.
    6560             :  *
    6561             :  * As a side-effect, the local RedoRecPtr copy is updated.
    6562             :  */
    6563             : XLogRecPtr
    6564      602270 : GetRedoRecPtr(void)
    6565             : {
    6566             :     XLogRecPtr  ptr;
    6567             : 
    6568             :     /*
    6569             :      * The possibly not up-to-date copy in XlogCtl is enough. Even if we
    6570             :      * grabbed a WAL insertion lock to read the authoritative value in
    6571             :      * Insert->RedoRecPtr, someone might update it just after we've released
    6572             :      * the lock.
    6573             :      */
    6574      602270 :     SpinLockAcquire(&XLogCtl->info_lck);
    6575      602270 :     ptr = XLogCtl->RedoRecPtr;
    6576      602270 :     SpinLockRelease(&XLogCtl->info_lck);
    6577             : 
    6578      602270 :     if (RedoRecPtr < ptr)
    6579        3194 :         RedoRecPtr = ptr;
    6580             : 
    6581      602270 :     return RedoRecPtr;
    6582             : }
    6583             : 
    6584             : /*
    6585             :  * Return information needed to decide whether a modified block needs a
    6586             :  * full-page image to be included in the WAL record.
    6587             :  *
    6588             :  * The returned values are cached copies from backend-private memory, and
    6589             :  * possibly out-of-date or, indeed, uninitialized, in which case they will
    6590             :  * be InvalidXLogRecPtr and false, respectively.  XLogInsertRecord will
    6591             :  * re-check them against up-to-date values, while holding the WAL insert lock.
    6592             :  */
    6593             : void
    6594    31068090 : GetFullPageWriteInfo(XLogRecPtr *RedoRecPtr_p, bool *doPageWrites_p)
    6595             : {
    6596    31068090 :     *RedoRecPtr_p = RedoRecPtr;
    6597    31068090 :     *doPageWrites_p = doPageWrites;
    6598    31068090 : }
    6599             : 
    6600             : /*
    6601             :  * GetInsertRecPtr -- Returns the current insert position.
    6602             :  *
    6603             :  * NOTE: The value *actually* returned is the position of the last full
    6604             :  * xlog page. It lags behind the real insert position by at most 1 page.
    6605             :  * For that, we don't need to scan through WAL insertion locks, and an
    6606             :  * approximation is enough for the current usage of this function.
    6607             :  */
    6608             : XLogRecPtr
    6609       13984 : GetInsertRecPtr(void)
    6610             : {
    6611             :     XLogRecPtr  recptr;
    6612             : 
    6613       13984 :     SpinLockAcquire(&XLogCtl->info_lck);
    6614       13984 :     recptr = XLogCtl->LogwrtRqst.Write;
    6615       13984 :     SpinLockRelease(&XLogCtl->info_lck);
    6616             : 
    6617       13984 :     return recptr;
    6618             : }
    6619             : 
    6620             : /*
    6621             :  * GetFlushRecPtr -- Returns the current flush position, ie, the last WAL
    6622             :  * position known to be fsync'd to disk. This should only be used on a
    6623             :  * system that is known not to be in recovery.
    6624             :  */
    6625             : XLogRecPtr
    6626      441762 : GetFlushRecPtr(TimeLineID *insertTLI)
    6627             : {
    6628             :     Assert(XLogCtl->SharedRecoveryState == RECOVERY_STATE_DONE);
    6629             : 
    6630      441762 :     RefreshXLogWriteResult(LogwrtResult);
    6631             : 
    6632             :     /*
    6633             :      * If we're writing and flushing WAL, the time line can't be changing, so
    6634             :      * no lock is required.
    6635             :      */
    6636      441762 :     if (insertTLI)
    6637       51404 :         *insertTLI = XLogCtl->InsertTimeLineID;
    6638             : 
    6639      441762 :     return LogwrtResult.Flush;
    6640             : }
    6641             : 
    6642             : /*
    6643             :  * GetWALInsertionTimeLine -- Returns the current timeline of a system that
    6644             :  * is not in recovery.
    6645             :  */
    6646             : TimeLineID
    6647      214058 : GetWALInsertionTimeLine(void)
    6648             : {
    6649             :     Assert(XLogCtl->SharedRecoveryState == RECOVERY_STATE_DONE);
    6650             : 
    6651             :     /* Since the value can't be changing, no lock is required. */
    6652      214058 :     return XLogCtl->InsertTimeLineID;
    6653             : }
    6654             : 
    6655             : /*
    6656             :  * GetWALInsertionTimeLineIfSet -- If the system is not in recovery, returns
    6657             :  * the WAL insertion timeline; else, returns 0. Wherever possible, use
    6658             :  * GetWALInsertionTimeLine() instead, since it's cheaper. Note that this
    6659             :  * function decides recovery has ended as soon as the insert TLI is set, which
    6660             :  * happens before we set XLogCtl->SharedRecoveryState to RECOVERY_STATE_DONE.
    6661             :  */
    6662             : TimeLineID
    6663           0 : GetWALInsertionTimeLineIfSet(void)
    6664             : {
    6665             :     TimeLineID  insertTLI;
    6666             : 
    6667           0 :     SpinLockAcquire(&XLogCtl->info_lck);
    6668           0 :     insertTLI = XLogCtl->InsertTimeLineID;
    6669           0 :     SpinLockRelease(&XLogCtl->info_lck);
    6670             : 
    6671           0 :     return insertTLI;
    6672             : }
    6673             : 
    6674             : /*
    6675             :  * GetLastImportantRecPtr -- Returns the LSN of the last important record
    6676             :  * inserted. All records not explicitly marked as unimportant are considered
    6677             :  * important.
    6678             :  *
    6679             :  * The LSN is determined by computing the maximum of
    6680             :  * WALInsertLocks[i].lastImportantAt.
    6681             :  */
    6682             : XLogRecPtr
    6683        3242 : GetLastImportantRecPtr(void)
    6684             : {
    6685        3242 :     XLogRecPtr  res = InvalidXLogRecPtr;
    6686             :     int         i;
    6687             : 
    6688       29178 :     for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++)
    6689             :     {
    6690             :         XLogRecPtr  last_important;
    6691             : 
    6692             :         /*
    6693             :          * Need to take a lock to prevent torn reads of the LSN, which are
    6694             :          * possible on some of the supported platforms. WAL insert locks only
    6695             :          * support exclusive mode, so we have to use that.
    6696             :          */
    6697       25936 :         LWLockAcquire(&WALInsertLocks[i].l.lock, LW_EXCLUSIVE);
    6698       25936 :         last_important = WALInsertLocks[i].l.lastImportantAt;
    6699       25936 :         LWLockRelease(&WALInsertLocks[i].l.lock);
    6700             : 
    6701       25936 :         if (res < last_important)
    6702        5604 :             res = last_important;
    6703             :     }
    6704             : 
    6705        3242 :     return res;
    6706             : }
    6707             : 
    6708             : /*
    6709             :  * Get the time and LSN of the last xlog segment switch
    6710             :  */
    6711             : pg_time_t
    6712           0 : GetLastSegSwitchData(XLogRecPtr *lastSwitchLSN)
    6713             : {
    6714             :     pg_time_t   result;
    6715             : 
    6716             :     /* Need WALWriteLock, but shared lock is sufficient */
    6717           0 :     LWLockAcquire(WALWriteLock, LW_SHARED);
    6718           0 :     result = XLogCtl->lastSegSwitchTime;
    6719           0 :     *lastSwitchLSN = XLogCtl->lastSegSwitchLSN;
    6720           0 :     LWLockRelease(WALWriteLock);
    6721             : 
    6722           0 :     return result;
    6723             : }
    6724             : 
    6725             : /*
    6726             :  * This must be called ONCE during postmaster or standalone-backend shutdown
    6727             :  */
    6728             : void
    6729        1364 : ShutdownXLOG(int code, Datum arg)
    6730             : {
    6731             :     /*
    6732             :      * We should have an aux process resource owner to use, and we should not
    6733             :      * be in a transaction that's installed some other resowner.
    6734             :      */
    6735             :     Assert(AuxProcessResourceOwner != NULL);
    6736             :     Assert(CurrentResourceOwner == NULL ||
    6737             :            CurrentResourceOwner == AuxProcessResourceOwner);
    6738        1364 :     CurrentResourceOwner = AuxProcessResourceOwner;
    6739             : 
    6740             :     /* Don't be chatty in standalone mode */
    6741        1364 :     ereport(IsPostmasterEnvironment ? LOG : NOTICE,
    6742             :             (errmsg("shutting down")));
    6743             : 
    6744             :     /*
    6745             :      * Signal walsenders to move to stopping state.
    6746             :      */
    6747        1364 :     WalSndInitStopping();
    6748             : 
    6749             :     /*
    6750             :      * Wait for WAL senders to be in stopping state.  This prevents commands
    6751             :      * from writing new WAL.
    6752             :      */
    6753        1364 :     WalSndWaitStopping();
    6754             : 
    6755        1364 :     if (RecoveryInProgress())
    6756         114 :         CreateRestartPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_FAST);
    6757             :     else
    6758             :     {
    6759             :         /*
    6760             :          * If archiving is enabled, rotate the last XLOG file so that all the
    6761             :          * remaining records are archived (postmaster wakes up the archiver
    6762             :          * process one more time at the end of shutdown). The checkpoint
    6763             :          * record will go to the next XLOG file and won't be archived (yet).
    6764             :          */
    6765        1250 :         if (XLogArchivingActive())
    6766          28 :             RequestXLogSwitch(false);
    6767             : 
    6768        1250 :         CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_FAST);
    6769             :     }
    6770        1364 : }
    6771             : 
    6772             : /*
    6773             :  * Log start of a checkpoint.
    6774             :  */
    6775             : static void
    6776        2954 : LogCheckpointStart(int flags, bool restartpoint)
    6777             : {
    6778        2954 :     if (restartpoint)
    6779         392 :         ereport(LOG,
    6780             :         /* translator: the placeholders show checkpoint options */
    6781             :                 (errmsg("restartpoint starting:%s%s%s%s%s%s%s%s",
    6782             :                         (flags & CHECKPOINT_IS_SHUTDOWN) ? " shutdown" : "",
    6783             :                         (flags & CHECKPOINT_END_OF_RECOVERY) ? " end-of-recovery" : "",
    6784             :                         (flags & CHECKPOINT_FAST) ? " fast" : "",
    6785             :                         (flags & CHECKPOINT_FORCE) ? " force" : "",
    6786             :                         (flags & CHECKPOINT_WAIT) ? " wait" : "",
    6787             :                         (flags & CHECKPOINT_CAUSE_XLOG) ? " wal" : "",
    6788             :                         (flags & CHECKPOINT_CAUSE_TIME) ? " time" : "",
    6789             :                         (flags & CHECKPOINT_FLUSH_UNLOGGED) ? " flush-unlogged" : "")));
    6790             :     else
    6791        2562 :         ereport(LOG,
    6792             :         /* translator: the placeholders show checkpoint options */
    6793             :                 (errmsg("checkpoint starting:%s%s%s%s%s%s%s%s",
    6794             :                         (flags & CHECKPOINT_IS_SHUTDOWN) ? " shutdown" : "",
    6795             :                         (flags & CHECKPOINT_END_OF_RECOVERY) ? " end-of-recovery" : "",
    6796             :                         (flags & CHECKPOINT_FAST) ? " fast" : "",
    6797             :                         (flags & CHECKPOINT_FORCE) ? " force" : "",
    6798             :                         (flags & CHECKPOINT_WAIT) ? " wait" : "",
    6799             :                         (flags & CHECKPOINT_CAUSE_XLOG) ? " wal" : "",
    6800             :                         (flags & CHECKPOINT_CAUSE_TIME) ? " time" : "",
    6801             :                         (flags & CHECKPOINT_FLUSH_UNLOGGED) ? " flush-unlogged" : "")));
    6802        2954 : }
    6803             : 
    6804             : /*
    6805             :  * Log end of a checkpoint.
    6806             :  */
    6807             : static void
    6808        3550 : LogCheckpointEnd(bool restartpoint)
    6809             : {
    6810             :     long        write_msecs,
    6811             :                 sync_msecs,
    6812             :                 total_msecs,
    6813             :                 longest_msecs,
    6814             :                 average_msecs;
    6815             :     uint64      average_sync_time;
    6816             : 
    6817        3550 :     CheckpointStats.ckpt_end_t = GetCurrentTimestamp();
    6818             : 
    6819        3550 :     write_msecs = TimestampDifferenceMilliseconds(CheckpointStats.ckpt_write_t,
    6820             :                                                   CheckpointStats.ckpt_sync_t);
    6821             : 
    6822        3550 :     sync_msecs = TimestampDifferenceMilliseconds(CheckpointStats.ckpt_sync_t,
    6823             :                                                  CheckpointStats.ckpt_sync_end_t);
    6824             : 
    6825             :     /* Accumulate checkpoint timing summary data, in milliseconds. */
    6826        3550 :     PendingCheckpointerStats.write_time += write_msecs;
    6827        3550 :     PendingCheckpointerStats.sync_time += sync_msecs;
    6828             : 
    6829             :     /*
    6830             :      * All of the published timing statistics are accounted for.  Only
    6831             :      * continue if a log message is to be written.
    6832             :      */
    6833        3550 :     if (!log_checkpoints)
    6834         596 :         return;
    6835             : 
    6836        2954 :     total_msecs = TimestampDifferenceMilliseconds(CheckpointStats.ckpt_start_t,
    6837             :                                                   CheckpointStats.ckpt_end_t);
    6838             : 
    6839             :     /*
    6840             :      * Timing values returned from CheckpointStats are in microseconds.
    6841             :      * Convert to milliseconds for consistent printing.
    6842             :      */
    6843        2954 :     longest_msecs = (long) ((CheckpointStats.ckpt_longest_sync + 999) / 1000);
    6844             : 
    6845        2954 :     average_sync_time = 0;
    6846        2954 :     if (CheckpointStats.ckpt_sync_rels > 0)
    6847           0 :         average_sync_time = CheckpointStats.ckpt_agg_sync_time /
    6848           0 :             CheckpointStats.ckpt_sync_rels;
    6849        2954 :     average_msecs = (long) ((average_sync_time + 999) / 1000);
    6850             : 
    6851             :     /*
    6852             :      * ControlFileLock is not required to see ControlFile->checkPoint and
    6853             :      * ->checkPointCopy here as we are the only updator of those variables at
    6854             :      * this moment.
    6855             :      */
    6856        2954 :     if (restartpoint)
    6857         392 :         ereport(LOG,
    6858             :                 (errmsg("restartpoint complete: wrote %d buffers (%.1f%%), "
    6859             :                         "wrote %d SLRU buffers; %d WAL file(s) added, "
    6860             :                         "%d removed, %d recycled; write=%ld.%03d s, "
    6861             :                         "sync=%ld.%03d s, total=%ld.%03d s; sync files=%d, "
    6862             :                         "longest=%ld.%03d s, average=%ld.%03d s; distance=%d kB, "
    6863             :                         "estimate=%d kB; lsn=%X/%08X, redo lsn=%X/%08X",
    6864             :                         CheckpointStats.ckpt_bufs_written,
    6865             :                         (double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
    6866             :                         CheckpointStats.ckpt_slru_written,
    6867             :                         CheckpointStats.ckpt_segs_added,
    6868             :                         CheckpointStats.ckpt_segs_removed,
    6869             :                         CheckpointStats.ckpt_segs_recycled,
    6870             :                         write_msecs / 1000, (int) (write_msecs % 1000),
    6871             :                         sync_msecs / 1000, (int) (sync_msecs % 1000),
    6872             :                         total_msecs / 1000, (int) (total_msecs % 1000),
    6873             :                         CheckpointStats.ckpt_sync_rels,
    6874             :                         longest_msecs / 1000, (int) (longest_msecs % 1000),
    6875             :                         average_msecs / 1000, (int) (average_msecs % 1000),
    6876             :                         (int) (PrevCheckPointDistance / 1024.0),
    6877             :                         (int) (CheckPointDistanceEstimate / 1024.0),
    6878             :                         LSN_FORMAT_ARGS(ControlFile->checkPoint),
    6879             :                         LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo))));
    6880             :     else
    6881        2562 :         ereport(LOG,
    6882             :                 (errmsg("checkpoint complete: wrote %d buffers (%.1f%%), "
    6883             :                         "wrote %d SLRU buffers; %d WAL file(s) added, "
    6884             :                         "%d removed, %d recycled; write=%ld.%03d s, "
    6885             :                         "sync=%ld.%03d s, total=%ld.%03d s; sync files=%d, "
    6886             :                         "longest=%ld.%03d s, average=%ld.%03d s; distance=%d kB, "
    6887             :                         "estimate=%d kB; lsn=%X/%08X, redo lsn=%X/%08X",
    6888             :                         CheckpointStats.ckpt_bufs_written,
    6889             :                         (double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
    6890             :                         CheckpointStats.ckpt_slru_written,
    6891             :                         CheckpointStats.ckpt_segs_added,
    6892             :                         CheckpointStats.ckpt_segs_removed,
    6893             :                         CheckpointStats.ckpt_segs_recycled,
    6894             :                         write_msecs / 1000, (int) (write_msecs % 1000),
    6895             :                         sync_msecs / 1000, (int) (sync_msecs % 1000),
    6896             :                         total_msecs / 1000, (int) (total_msecs % 1000),
    6897             :                         CheckpointStats.ckpt_sync_rels,
    6898             :                         longest_msecs / 1000, (int) (longest_msecs % 1000),
    6899             :                         average_msecs / 1000, (int) (average_msecs % 1000),
    6900             :                         (int) (PrevCheckPointDistance / 1024.0),
    6901             :                         (int) (CheckPointDistanceEstimate / 1024.0),
    6902             :                         LSN_FORMAT_ARGS(ControlFile->checkPoint),
    6903             :                         LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo))));
    6904             : }
    6905             : 
    6906             : /*
    6907             :  * Update the estimate of distance between checkpoints.
    6908             :  *
    6909             :  * The estimate is used to calculate the number of WAL segments to keep
    6910             :  * preallocated, see XLOGfileslop().
    6911             :  */
    6912             : static void
    6913        3550 : UpdateCheckPointDistanceEstimate(uint64 nbytes)
    6914             : {
    6915             :     /*
    6916             :      * To estimate the number of segments consumed between checkpoints, keep a
    6917             :      * moving average of the amount of WAL generated in previous checkpoint
    6918             :      * cycles. However, if the load is bursty, with quiet periods and busy
    6919             :      * periods, we want to cater for the peak load. So instead of a plain
    6920             :      * moving average, let the average decline slowly if the previous cycle
    6921             :      * used less WAL than estimated, but bump it up immediately if it used
    6922             :      * more.
    6923             :      *
    6924             :      * When checkpoints are triggered by max_wal_size, this should converge to
    6925             :      * CheckpointSegments * wal_segment_size,
    6926             :      *
    6927             :      * Note: This doesn't pay any attention to what caused the checkpoint.
    6928             :      * Checkpoints triggered manually with CHECKPOINT command, or by e.g.
    6929             :      * starting a base backup, are counted the same as those created
    6930             :      * automatically. The slow-decline will largely mask them out, if they are
    6931             :      * not frequent. If they are frequent, it seems reasonable to count them
    6932             :      * in as any others; if you issue a manual checkpoint every 5 minutes and
    6933             :      * never let a timed checkpoint happen, it makes sense to base the
    6934             :      * preallocation on that 5 minute interval rather than whatever
    6935             :      * checkpoint_timeout is set to.
    6936             :      */
    6937        3550 :     PrevCheckPointDistance = nbytes;
    6938        3550 :     if (CheckPointDistanceEstimate < nbytes)
    6939        1526 :         CheckPointDistanceEstimate = nbytes;
    6940             :     else
    6941        2024 :         CheckPointDistanceEstimate =
    6942        2024 :             (0.90 * CheckPointDistanceEstimate + 0.10 * (double) nbytes);
    6943        3550 : }
    6944             : 
    6945             : /*
    6946             :  * Update the ps display for a process running a checkpoint.  Note that
    6947             :  * this routine should not do any allocations so as it can be called
    6948             :  * from a critical section.
    6949             :  */
    6950             : static void
    6951        7100 : update_checkpoint_display(int flags, bool restartpoint, bool reset)
    6952             : {
    6953             :     /*
    6954             :      * The status is reported only for end-of-recovery and shutdown
    6955             :      * checkpoints or shutdown restartpoints.  Updating the ps display is
    6956             :      * useful in those situations as it may not be possible to rely on
    6957             :      * pg_stat_activity to see the status of the checkpointer or the startup
    6958             :      * process.
    6959             :      */
    6960        7100 :     if ((flags & (CHECKPOINT_END_OF_RECOVERY | CHECKPOINT_IS_SHUTDOWN)) == 0)
    6961        4400 :         return;
    6962             : 
    6963        2700 :     if (reset)
    6964        1350 :         set_ps_display("");
    6965             :     else
    6966             :     {
    6967             :         char        activitymsg[128];
    6968             : 
    6969        4050 :         snprintf(activitymsg, sizeof(activitymsg), "performing %s%s%s",
    6970        1350 :                  (flags & CHECKPOINT_END_OF_RECOVERY) ? "end-of-recovery " : "",
    6971        1350 :                  (flags & CHECKPOINT_IS_SHUTDOWN) ? "shutdown " : "",
    6972             :                  restartpoint ? "restartpoint" : "checkpoint");
    6973        1350 :         set_ps_display(activitymsg);
    6974             :     }
    6975             : }
    6976             : 
    6977             : 
    6978             : /*
    6979             :  * Perform a checkpoint --- either during shutdown, or on-the-fly
    6980             :  *
    6981             :  * flags is a bitwise OR of the following:
    6982             :  *  CHECKPOINT_IS_SHUTDOWN: checkpoint is for database shutdown.
    6983             :  *  CHECKPOINT_END_OF_RECOVERY: checkpoint is for end of WAL recovery.
    6984             :  *  CHECKPOINT_FAST: finish the checkpoint ASAP, ignoring
    6985             :  *      checkpoint_completion_target parameter.
    6986             :  *  CHECKPOINT_FORCE: force a checkpoint even if no XLOG activity has occurred
    6987             :  *      since the last one (implied by CHECKPOINT_IS_SHUTDOWN or
    6988             :  *      CHECKPOINT_END_OF_RECOVERY).
    6989             :  *  CHECKPOINT_FLUSH_UNLOGGED: also flush buffers of unlogged tables.
    6990             :  *
    6991             :  * Note: flags contains other bits, of interest here only for logging purposes.
    6992             :  * In particular note that this routine is synchronous and does not pay
    6993             :  * attention to CHECKPOINT_WAIT.
    6994             :  *
    6995             :  * If !shutdown then we are writing an online checkpoint. An XLOG_CHECKPOINT_REDO
    6996             :  * record is inserted into WAL at the logical location of the checkpoint, before
    6997             :  * flushing anything to disk, and when the checkpoint is eventually completed,
    6998             :  * and it is from this point that WAL replay will begin in the case of a recovery
    6999             :  * from this checkpoint. Once everything is written to disk, an
    7000             :  * XLOG_CHECKPOINT_ONLINE record is written to complete the checkpoint, and
    7001             :  * points back to the earlier XLOG_CHECKPOINT_REDO record. This mechanism allows
    7002             :  * other write-ahead log records to be written while the checkpoint is in
    7003             :  * progress, but we must be very careful about order of operations. This function
    7004             :  * may take many minutes to execute on a busy system.
    7005             :  *
    7006             :  * On the other hand, when shutdown is true, concurrent insertion into the
    7007             :  * write-ahead log is impossible, so there is no need for two separate records.
    7008             :  * In this case, we only insert an XLOG_CHECKPOINT_SHUTDOWN record, and it's
    7009             :  * both the record marking the completion of the checkpoint and the location
    7010             :  * from which WAL replay would begin if needed.
    7011             :  *
    7012             :  * Returns true if a new checkpoint was performed, or false if it was skipped
    7013             :  * because the system was idle.
    7014             :  */
    7015             : bool
    7016        3160 : CreateCheckPoint(int flags)
    7017             : {
    7018             :     bool        shutdown;
    7019             :     CheckPoint  checkPoint;
    7020             :     XLogRecPtr  recptr;
    7021             :     XLogSegNo   _logSegNo;
    7022        3160 :     XLogCtlInsert *Insert = &XLogCtl->Insert;
    7023             :     uint32      freespace;
    7024             :     XLogRecPtr  PriorRedoPtr;
    7025             :     XLogRecPtr  last_important_lsn;
    7026             :     VirtualTransactionId *vxids;
    7027             :     int         nvxids;
    7028        3160 :     int         oldXLogAllowed = 0;
    7029             : 
    7030             :     /*
    7031             :      * An end-of-recovery checkpoint is really a shutdown checkpoint, just
    7032             :      * issued at a different time.
    7033             :      */
    7034        3160 :     if (flags & (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_END_OF_RECOVERY))
    7035        1306 :         shutdown = true;
    7036             :     else
    7037        1854 :         shutdown = false;
    7038             : 
    7039             :     /* sanity check */
    7040        3160 :     if (RecoveryInProgress() && (flags & CHECKPOINT_END_OF_RECOVERY) == 0)
    7041           0 :         elog(ERROR, "can't create a checkpoint during recovery");
    7042             : 
    7043             :     /*
    7044             :      * Prepare to accumulate statistics.
    7045             :      *
    7046             :      * Note: because it is possible for log_checkpoints to change while a
    7047             :      * checkpoint proceeds, we always accumulate stats, even if
    7048             :      * log_checkpoints is currently off.
    7049             :      */
    7050       34760 :     MemSet(&CheckpointStats, 0, sizeof(CheckpointStats));
    7051        3160 :     CheckpointStats.ckpt_start_t = GetCurrentTimestamp();
    7052             : 
    7053             :     /*
    7054             :      * Let smgr prepare for checkpoint; this has to happen outside the
    7055             :      * critical section and before we determine the REDO pointer.  Note that
    7056             :      * smgr must not do anything that'd have to be undone if we decide no
    7057             :      * checkpoint is needed.
    7058             :      */
    7059        3160 :     SyncPreCheckpoint();
    7060             : 
    7061             :     /* Run these points outside the critical section. */
    7062        3160 :     INJECTION_POINT("create-checkpoint-initial", NULL);
    7063        3160 :     INJECTION_POINT_LOAD("create-checkpoint-run");
    7064             : 
    7065             :     /*
    7066             :      * Use a critical section to force system panic if we have trouble.
    7067             :      */
    7068        3160 :     START_CRIT_SECTION();
    7069             : 
    7070        3160 :     if (shutdown)
    7071             :     {
    7072        1306 :         LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    7073        1306 :         ControlFile->state = DB_SHUTDOWNING;
    7074        1306 :         UpdateControlFile();
    7075        1306 :         LWLockRelease(ControlFileLock);
    7076             :     }
    7077             : 
    7078             :     /* Begin filling in the checkpoint WAL record */
    7079       41080 :     MemSet(&checkPoint, 0, sizeof(checkPoint));
    7080        3160 :     checkPoint.time = (pg_time_t) time(NULL);
    7081             : 
    7082             :     /*
    7083             :      * For Hot Standby, derive the oldestActiveXid before we fix the redo
    7084             :      * pointer. This allows us to begin accumulating changes to assemble our
    7085             :      * starting snapshot of locks and transactions.
    7086             :      */
    7087        3160 :     if (!shutdown && XLogStandbyInfoActive())
    7088        1798 :         checkPoint.oldestActiveXid = GetOldestActiveTransactionId(false, true);
    7089             :     else
    7090        1362 :         checkPoint.oldestActiveXid = InvalidTransactionId;
    7091             : 
    7092             :     /*
    7093             :      * Get location of last important record before acquiring insert locks (as
    7094             :      * GetLastImportantRecPtr() also locks WAL locks).
    7095             :      */
    7096        3160 :     last_important_lsn = GetLastImportantRecPtr();
    7097             : 
    7098             :     /*
    7099             :      * If this isn't a shutdown or forced checkpoint, and if there has been no
    7100             :      * WAL activity requiring a checkpoint, skip it.  The idea here is to
    7101             :      * avoid inserting duplicate checkpoints when the system is idle.
    7102             :      */
    7103        3160 :     if ((flags & (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_END_OF_RECOVERY |
    7104             :                   CHECKPOINT_FORCE)) == 0)
    7105             :     {
    7106         386 :         if (last_important_lsn == ControlFile->checkPoint)
    7107             :         {
    7108           2 :             END_CRIT_SECTION();
    7109           2 :             ereport(DEBUG1,
    7110             :                     (errmsg_internal("checkpoint skipped because system is idle")));
    7111           2 :             return false;
    7112             :         }
    7113             :     }
    7114             : 
    7115             :     /*
    7116             :      * An end-of-recovery checkpoint is created before anyone is allowed to
    7117             :      * write WAL. To allow us to write the checkpoint record, temporarily
    7118             :      * enable XLogInsertAllowed.
    7119             :      */
    7120        3158 :     if (flags & CHECKPOINT_END_OF_RECOVERY)
    7121          56 :         oldXLogAllowed = LocalSetXLogInsertAllowed();
    7122             : 
    7123        3158 :     checkPoint.ThisTimeLineID = XLogCtl->InsertTimeLineID;
    7124        3158 :     if (flags & CHECKPOINT_END_OF_RECOVERY)
    7125          56 :         checkPoint.PrevTimeLineID = XLogCtl->PrevTimeLineID;
    7126             :     else
    7127        3102 :         checkPoint.PrevTimeLineID = checkPoint.ThisTimeLineID;
    7128             : 
    7129             :     /*
    7130             :      * We must block concurrent insertions while examining insert state.
    7131             :      */
    7132        3158 :     WALInsertLockAcquireExclusive();
    7133             : 
    7134        3158 :     checkPoint.fullPageWrites = Insert->fullPageWrites;
    7135        3158 :     checkPoint.wal_level = wal_level;
    7136             : 
    7137        3158 :     if (shutdown)
    7138             :     {
    7139        1306 :         XLogRecPtr  curInsert = XLogBytePosToRecPtr(Insert->CurrBytePos);
    7140             : 
    7141             :         /*
    7142             :          * Compute new REDO record ptr = location of next XLOG record.
    7143             :          *
    7144             :          * Since this is a shutdown checkpoint, there can't be any concurrent
    7145             :          * WAL insertion.
    7146             :          */
    7147        1306 :         freespace = INSERT_FREESPACE(curInsert);
    7148        1306 :         if (freespace == 0)
    7149             :         {
    7150           0 :             if (XLogSegmentOffset(curInsert, wal_segment_size) == 0)
    7151           0 :                 curInsert += SizeOfXLogLongPHD;
    7152             :             else
    7153           0 :                 curInsert += SizeOfXLogShortPHD;
    7154             :         }
    7155        1306 :         checkPoint.redo = curInsert;
    7156             : 
    7157             :         /*
    7158             :          * Here we update the shared RedoRecPtr for future XLogInsert calls;
    7159             :          * this must be done while holding all the insertion locks.
    7160             :          *
    7161             :          * Note: if we fail to complete the checkpoint, RedoRecPtr will be
    7162             :          * left pointing past where it really needs to point.  This is okay;
    7163             :          * the only consequence is that XLogInsert might back up whole buffers
    7164             :          * that it didn't really need to.  We can't postpone advancing
    7165             :          * RedoRecPtr because XLogInserts that happen while we are dumping
    7166             :          * buffers must assume that their buffer changes are not included in
    7167             :          * the checkpoint.
    7168             :          */
    7169        1306 :         RedoRecPtr = XLogCtl->Insert.RedoRecPtr = checkPoint.redo;
    7170             :     }
    7171             : 
    7172             :     /*
    7173             :      * Now we can release the WAL insertion locks, allowing other xacts to
    7174             :      * proceed while we are flushing disk buffers.
    7175             :      */
    7176        3158 :     WALInsertLockRelease();
    7177             : 
    7178             :     /*
    7179             :      * If this is an online checkpoint, we have not yet determined the redo
    7180             :      * point. We do so now by inserting the special XLOG_CHECKPOINT_REDO
    7181             :      * record; the LSN at which it starts becomes the new redo pointer. We
    7182             :      * don't do this for a shutdown checkpoint, because in that case no WAL
    7183             :      * can be written between the redo point and the insertion of the
    7184             :      * checkpoint record itself, so the checkpoint record itself serves to
    7185             :      * mark the redo point.
    7186             :      */
    7187        3158 :     if (!shutdown)
    7188             :     {
    7189             :         /* Include WAL level in record for WAL summarizer's benefit. */
    7190        1852 :         XLogBeginInsert();
    7191        1852 :         XLogRegisterData(&wal_level, sizeof(wal_level));
    7192        1852 :         (void) XLogInsert(RM_XLOG_ID, XLOG_CHECKPOINT_REDO);
    7193             : 
    7194             :         /*
    7195             :          * XLogInsertRecord will have updated XLogCtl->Insert.RedoRecPtr in
    7196             :          * shared memory and RedoRecPtr in backend-local memory, but we need
    7197             :          * to copy that into the record that will be inserted when the
    7198             :          * checkpoint is complete.
    7199             :          */
    7200        1852 :         checkPoint.redo = RedoRecPtr;
    7201             :     }
    7202             : 
    7203             :     /* Update the info_lck-protected copy of RedoRecPtr as well */
    7204        3158 :     SpinLockAcquire(&XLogCtl->info_lck);
    7205        3158 :     XLogCtl->RedoRecPtr = checkPoint.redo;
    7206        3158 :     SpinLockRelease(&XLogCtl->info_lck);
    7207             : 
    7208             :     /*
    7209             :      * If enabled, log checkpoint start.  We postpone this until now so as not
    7210             :      * to log anything if we decided to skip the checkpoint.
    7211             :      */
    7212        3158 :     if (log_checkpoints)
    7213        2562 :         LogCheckpointStart(flags, false);
    7214             : 
    7215        3158 :     INJECTION_POINT_CACHED("create-checkpoint-run", NULL);
    7216             : 
    7217             :     /* Update the process title */
    7218        3158 :     update_checkpoint_display(flags, false, false);
    7219             : 
    7220             :     TRACE_POSTGRESQL_CHECKPOINT_START(flags);
    7221             : 
    7222             :     /*
    7223             :      * Get the other info we need for the checkpoint record.
    7224             :      *
    7225             :      * We don't need to save oldestClogXid in the checkpoint, it only matters
    7226             :      * for the short period in which clog is being truncated, and if we crash
    7227             :      * during that we'll redo the clog truncation and fix up oldestClogXid
    7228             :      * there.
    7229             :      */
    7230        3158 :     LWLockAcquire(XidGenLock, LW_SHARED);
    7231        3158 :     checkPoint.nextXid = TransamVariables->nextXid;
    7232        3158 :     checkPoint.oldestXid = TransamVariables->oldestXid;
    7233        3158 :     checkPoint.oldestXidDB = TransamVariables->oldestXidDB;
    7234        3158 :     LWLockRelease(XidGenLock);
    7235             : 
    7236        3158 :     LWLockAcquire(CommitTsLock, LW_SHARED);
    7237        3158 :     checkPoint.oldestCommitTsXid = TransamVariables->oldestCommitTsXid;
    7238        3158 :     checkPoint.newestCommitTsXid = TransamVariables->newestCommitTsXid;
    7239        3158 :     LWLockRelease(CommitTsLock);
    7240             : 
    7241        3158 :     LWLockAcquire(OidGenLock, LW_SHARED);
    7242        3158 :     checkPoint.nextOid = TransamVariables->nextOid;
    7243        3158 :     if (!shutdown)
    7244        1852 :         checkPoint.nextOid += TransamVariables->oidCount;
    7245        3158 :     LWLockRelease(OidGenLock);
    7246             : 
    7247        3158 :     checkPoint.logicalDecodingEnabled = IsLogicalDecodingEnabled();
    7248             : 
    7249        3158 :     MultiXactGetCheckptMulti(shutdown,
    7250             :                              &checkPoint.nextMulti,
    7251             :                              &checkPoint.nextMultiOffset,
    7252             :                              &checkPoint.oldestMulti,
    7253             :                              &checkPoint.oldestMultiDB);
    7254             : 
    7255             :     /*
    7256             :      * Having constructed the checkpoint record, ensure all shmem disk buffers
    7257             :      * and commit-log buffers are flushed to disk.
    7258             :      *
    7259             :      * This I/O could fail for various reasons.  If so, we will fail to
    7260             :      * complete the checkpoint, but there is no reason to force a system
    7261             :      * panic. Accordingly, exit critical section while doing it.
    7262             :      */
    7263        3158 :     END_CRIT_SECTION();
    7264             : 
    7265             :     /*
    7266             :      * In some cases there are groups of actions that must all occur on one
    7267             :      * side or the other of a checkpoint record. Before flushing the
    7268             :      * checkpoint record we must explicitly wait for any backend currently
    7269             :      * performing those groups of actions.
    7270             :      *
    7271             :      * One example is end of transaction, so we must wait for any transactions
    7272             :      * that are currently in commit critical sections.  If an xact inserted
    7273             :      * its commit record into XLOG just before the REDO point, then a crash
    7274             :      * restart from the REDO point would not replay that record, which means
    7275             :      * that our flushing had better include the xact's update of pg_xact.  So
    7276             :      * we wait till he's out of his commit critical section before proceeding.
    7277             :      * See notes in RecordTransactionCommit().
    7278             :      *
    7279             :      * Because we've already released the insertion locks, this test is a bit
    7280             :      * fuzzy: it is possible that we will wait for xacts we didn't really need
    7281             :      * to wait for.  But the delay should be short and it seems better to make
    7282             :      * checkpoint take a bit longer than to hold off insertions longer than
    7283             :      * necessary. (In fact, the whole reason we have this issue is that xact.c
    7284             :      * does commit record XLOG insertion and clog update as two separate steps
    7285             :      * protected by different locks, but again that seems best on grounds of
    7286             :      * minimizing lock contention.)
    7287             :      *
    7288             :      * A transaction that has not yet set delayChkptFlags when we look cannot
    7289             :      * be at risk, since it has not inserted its commit record yet; and one
    7290             :      * that's already cleared it is not at risk either, since it's done fixing
    7291             :      * clog and we will correctly flush the update below.  So we cannot miss
    7292             :      * any xacts we need to wait for.
    7293             :      */
    7294        3158 :     vxids = GetVirtualXIDsDelayingChkpt(&nvxids, DELAY_CHKPT_START);
    7295        3158 :     if (nvxids > 0)
    7296             :     {
    7297             :         do
    7298             :         {
    7299             :             /*
    7300             :              * Keep absorbing fsync requests while we wait. There could even
    7301             :              * be a deadlock if we don't, if the process that prevents the
    7302             :              * checkpoint is trying to add a request to the queue.
    7303             :              */
    7304          58 :             AbsorbSyncRequests();
    7305             : 
    7306          58 :             pgstat_report_wait_start(WAIT_EVENT_CHECKPOINT_DELAY_START);
    7307          58 :             pg_usleep(10000L);  /* wait for 10 msec */
    7308          58 :             pgstat_report_wait_end();
    7309          58 :         } while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids,
    7310             :                                               DELAY_CHKPT_START));
    7311             :     }
    7312        3158 :     pfree(vxids);
    7313             : 
    7314        3158 :     CheckPointGuts(checkPoint.redo, flags);
    7315             : 
    7316        3158 :     vxids = GetVirtualXIDsDelayingChkpt(&nvxids, DELAY_CHKPT_COMPLETE);
    7317        3158 :     if (nvxids > 0)
    7318             :     {
    7319             :         do
    7320             :         {
    7321           0 :             AbsorbSyncRequests();
    7322             : 
    7323           0 :             pgstat_report_wait_start(WAIT_EVENT_CHECKPOINT_DELAY_COMPLETE);
    7324           0 :             pg_usleep(10000L);  /* wait for 10 msec */
    7325           0 :             pgstat_report_wait_end();
    7326           0 :         } while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids,
    7327             :                                               DELAY_CHKPT_COMPLETE));
    7328             :     }
    7329        3158 :     pfree(vxids);
    7330             : 
    7331             :     /*
    7332             :      * Take a snapshot of running transactions and write this to WAL. This
    7333             :      * allows us to reconstruct the state of running transactions during
    7334             :      * archive recovery, if required. Skip, if this info disabled.
    7335             :      *
    7336             :      * If we are shutting down, or Startup process is completing crash
    7337             :      * recovery we don't need to write running xact data.
    7338             :      */
    7339        3158 :     if (!shutdown && XLogStandbyInfoActive())
    7340        1796 :         LogStandbySnapshot();
    7341             : 
    7342        3158 :     START_CRIT_SECTION();
    7343             : 
    7344             :     /*
    7345             :      * Now insert the checkpoint record into XLOG.
    7346             :      */
    7347        3158 :     XLogBeginInsert();
    7348        3158 :     XLogRegisterData(&checkPoint, sizeof(checkPoint));
    7349        3158 :     recptr = XLogInsert(RM_XLOG_ID,
    7350             :                         shutdown ? XLOG_CHECKPOINT_SHUTDOWN :
    7351             :                         XLOG_CHECKPOINT_ONLINE);
    7352             : 
    7353        3158 :     XLogFlush(recptr);
    7354             : 
    7355             :     /*
    7356             :      * We mustn't write any new WAL after a shutdown checkpoint, or it will be
    7357             :      * overwritten at next startup.  No-one should even try, this just allows
    7358             :      * sanity-checking.  In the case of an end-of-recovery checkpoint, we want
    7359             :      * to just temporarily disable writing until the system has exited
    7360             :      * recovery.
    7361             :      */
    7362        3158 :     if (shutdown)
    7363             :     {
    7364        1306 :         if (flags & CHECKPOINT_END_OF_RECOVERY)
    7365          56 :             LocalXLogInsertAllowed = oldXLogAllowed;
    7366             :         else
    7367        1250 :             LocalXLogInsertAllowed = 0; /* never again write WAL */
    7368             :     }
    7369             : 
    7370             :     /*
    7371             :      * We now have ProcLastRecPtr = start of actual checkpoint record, recptr
    7372             :      * = end of actual checkpoint record.
    7373             :      */
    7374        3158 :     if (shutdown && checkPoint.redo != ProcLastRecPtr)
    7375           0 :         ereport(PANIC,
    7376             :                 (errmsg("concurrent write-ahead log activity while database system is shutting down")));
    7377             : 
    7378             :     /*
    7379             :      * Remember the prior checkpoint's redo ptr for
    7380             :      * UpdateCheckPointDistanceEstimate()
    7381             :      */
    7382        3158 :     PriorRedoPtr = ControlFile->checkPointCopy.redo;
    7383             : 
    7384             :     /*
    7385             :      * Update the control file.
    7386             :      */
    7387        3158 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    7388        3158 :     if (shutdown)
    7389        1306 :         ControlFile->state = DB_SHUTDOWNED;
    7390        3158 :     ControlFile->checkPoint = ProcLastRecPtr;
    7391        3158 :     ControlFile->checkPointCopy = checkPoint;
    7392             :     /* crash recovery should always recover to the end of WAL */
    7393        3158 :     ControlFile->minRecoveryPoint = InvalidXLogRecPtr;
    7394        3158 :     ControlFile->minRecoveryPointTLI = 0;
    7395             : 
    7396             :     /*
    7397             :      * Persist unloggedLSN value. It's reset on crash recovery, so this goes
    7398             :      * unused on non-shutdown checkpoints, but seems useful to store it always
    7399             :      * for debugging purposes.
    7400             :      */
    7401        3158 :     ControlFile->unloggedLSN = pg_atomic_read_membarrier_u64(&XLogCtl->unloggedLSN);
    7402             : 
    7403        3158 :     UpdateControlFile();
    7404        3158 :     LWLockRelease(ControlFileLock);
    7405             : 
    7406             :     /*
    7407             :      * We are now done with critical updates; no need for system panic if we
    7408             :      * have trouble while fooling with old log segments.
    7409             :      */
    7410        3158 :     END_CRIT_SECTION();
    7411             : 
    7412             :     /*
    7413             :      * WAL summaries end when the next XLOG_CHECKPOINT_REDO or
    7414             :      * XLOG_CHECKPOINT_SHUTDOWN record is reached. This is the first point
    7415             :      * where (a) we're not inside of a critical section and (b) we can be
    7416             :      * certain that the relevant record has been flushed to disk, which must
    7417             :      * happen before it can be summarized.
    7418             :      *
    7419             :      * If this is a shutdown checkpoint, then this happens reasonably
    7420             :      * promptly: we've only just inserted and flushed the
    7421             :      * XLOG_CHECKPOINT_SHUTDOWN record. If this is not a shutdown checkpoint,
    7422             :      * then this might not be very prompt at all: the XLOG_CHECKPOINT_REDO
    7423             :      * record was written before we began flushing data to disk, and that
    7424             :      * could be many minutes ago at this point. However, we don't XLogFlush()
    7425             :      * after inserting that record, so we're not guaranteed that it's on disk
    7426             :      * until after the above call that flushes the XLOG_CHECKPOINT_ONLINE
    7427             :      * record.
    7428             :      */
    7429        3158 :     WakeupWalSummarizer();
    7430             : 
    7431             :     /*
    7432             :      * Let smgr do post-checkpoint cleanup (eg, deleting old files).
    7433             :      */
    7434        3158 :     SyncPostCheckpoint();
    7435             : 
    7436             :     /*
    7437             :      * Update the average distance between checkpoints if the prior checkpoint
    7438             :      * exists.
    7439             :      */
    7440        3158 :     if (XLogRecPtrIsValid(PriorRedoPtr))
    7441        3158 :         UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
    7442             : 
    7443        3158 :     INJECTION_POINT("checkpoint-before-old-wal-removal", NULL);
    7444             : 
    7445             :     /*
    7446             :      * Delete old log files, those no longer needed for last checkpoint to
    7447             :      * prevent the disk holding the xlog from growing full.
    7448             :      */
    7449        3158 :     XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
    7450        3158 :     KeepLogSeg(recptr, &_logSegNo);
    7451        3158 :     if (InvalidateObsoleteReplicationSlots(RS_INVAL_WAL_REMOVED | RS_INVAL_IDLE_TIMEOUT,
    7452             :                                            _logSegNo, InvalidOid,
    7453             :                                            InvalidTransactionId))
    7454             :     {
    7455             :         /*
    7456             :          * Some slots have been invalidated; recalculate the old-segment
    7457             :          * horizon, starting again from RedoRecPtr.
    7458             :          */
    7459           8 :         XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
    7460           8 :         KeepLogSeg(recptr, &_logSegNo);
    7461             :     }
    7462        3158 :     _logSegNo--;
    7463        3158 :     RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr,
    7464             :                        checkPoint.ThisTimeLineID);
    7465             : 
    7466             :     /*
    7467             :      * Make more log segments if needed.  (Do this after recycling old log
    7468             :      * segments, since that may supply some of the needed files.)
    7469             :      */
    7470        3158 :     if (!shutdown)
    7471        1852 :         PreallocXlogFiles(recptr, checkPoint.ThisTimeLineID);
    7472             : 
    7473             :     /*
    7474             :      * Truncate pg_subtrans if possible.  We can throw away all data before
    7475             :      * the oldest XMIN of any running transaction.  No future transaction will
    7476             :      * attempt to reference any pg_subtrans entry older than that (see Asserts
    7477             :      * in subtrans.c).  During recovery, though, we mustn't do this because
    7478             :      * StartupSUBTRANS hasn't been called yet.
    7479             :      */
    7480        3158 :     if (!RecoveryInProgress())
    7481        3102 :         TruncateSUBTRANS(GetOldestTransactionIdConsideredRunning());
    7482             : 
    7483             :     /* Real work is done; log and update stats. */
    7484        3158 :     LogCheckpointEnd(false);
    7485             : 
    7486             :     /* Reset the process title */
    7487        3158 :     update_checkpoint_display(flags, false, true);
    7488             : 
    7489             :     TRACE_POSTGRESQL_CHECKPOINT_DONE(CheckpointStats.ckpt_bufs_written,
    7490             :                                      NBuffers,
    7491             :                                      CheckpointStats.ckpt_segs_added,
    7492             :                                      CheckpointStats.ckpt_segs_removed,
    7493             :                                      CheckpointStats.ckpt_segs_recycled);
    7494             : 
    7495        3158 :     return true;
    7496             : }
    7497             : 
    7498             : /*
    7499             :  * Mark the end of recovery in WAL though without running a full checkpoint.
    7500             :  * We can expect that a restartpoint is likely to be in progress as we
    7501             :  * do this, though we are unwilling to wait for it to complete.
    7502             :  *
    7503             :  * CreateRestartPoint() allows for the case where recovery may end before
    7504             :  * the restartpoint completes so there is no concern of concurrent behaviour.
    7505             :  */
    7506             : static void
    7507          96 : CreateEndOfRecoveryRecord(void)
    7508             : {
    7509             :     xl_end_of_recovery xlrec;
    7510             :     XLogRecPtr  recptr;
    7511             : 
    7512             :     /* sanity check */
    7513          96 :     if (!RecoveryInProgress())
    7514           0 :         elog(ERROR, "can only be used to end recovery");
    7515             : 
    7516          96 :     xlrec.end_time = GetCurrentTimestamp();
    7517          96 :     xlrec.wal_level = wal_level;
    7518             : 
    7519          96 :     WALInsertLockAcquireExclusive();
    7520          96 :     xlrec.ThisTimeLineID = XLogCtl->InsertTimeLineID;
    7521          96 :     xlrec.PrevTimeLineID = XLogCtl->PrevTimeLineID;
    7522          96 :     WALInsertLockRelease();
    7523             : 
    7524          96 :     START_CRIT_SECTION();
    7525             : 
    7526          96 :     XLogBeginInsert();
    7527          96 :     XLogRegisterData(&xlrec, sizeof(xl_end_of_recovery));
    7528          96 :     recptr = XLogInsert(RM_XLOG_ID, XLOG_END_OF_RECOVERY);
    7529             : 
    7530          96 :     XLogFlush(recptr);
    7531             : 
    7532             :     /*
    7533             :      * Update the control file so that crash recovery can follow the timeline
    7534             :      * changes to this point.
    7535             :      */
    7536          96 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    7537          96 :     ControlFile->minRecoveryPoint = recptr;
    7538          96 :     ControlFile->minRecoveryPointTLI = xlrec.ThisTimeLineID;
    7539          96 :     UpdateControlFile();
    7540          96 :     LWLockRelease(ControlFileLock);
    7541             : 
    7542          96 :     END_CRIT_SECTION();
    7543          96 : }
    7544             : 
    7545             : /*
    7546             :  * Write an OVERWRITE_CONTRECORD message.
    7547             :  *
    7548             :  * When on WAL replay we expect a continuation record at the start of a page
    7549             :  * that is not there, recovery ends and WAL writing resumes at that point.
    7550             :  * But it's wrong to resume writing new WAL back at the start of the record
    7551             :  * that was broken, because downstream consumers of that WAL (physical
    7552             :  * replicas) are not prepared to "rewind".  So the first action after
    7553             :  * finishing replay of all valid WAL must be to write a record of this type
    7554             :  * at the point where the contrecord was missing; to support xlogreader
    7555             :  * detecting the special case, XLP_FIRST_IS_OVERWRITE_CONTRECORD is also added
    7556             :  * to the page header where the record occurs.  xlogreader has an ad-hoc
    7557             :  * mechanism to report metadata about the broken record, which is what we
    7558             :  * use here.
    7559             :  *
    7560             :  * At replay time, XLP_FIRST_IS_OVERWRITE_CONTRECORD instructs xlogreader to
    7561             :  * skip the record it was reading, and pass back the LSN of the skipped
    7562             :  * record, so that its caller can verify (on "replay" of that record) that the
    7563             :  * XLOG_OVERWRITE_CONTRECORD matches what was effectively overwritten.
    7564             :  *
    7565             :  * 'aborted_lsn' is the beginning position of the record that was incomplete.
    7566             :  * It is included in the WAL record.  'pagePtr' and 'newTLI' point to the
    7567             :  * beginning of the XLOG page where the record is to be inserted.  They must
    7568             :  * match the current WAL insert position, they're passed here just so that we
    7569             :  * can verify that.
    7570             :  */
    7571             : static XLogRecPtr
    7572          22 : CreateOverwriteContrecordRecord(XLogRecPtr aborted_lsn, XLogRecPtr pagePtr,
    7573             :                                 TimeLineID newTLI)
    7574             : {
    7575             :     xl_overwrite_contrecord xlrec;
    7576             :     XLogRecPtr  recptr;
    7577             :     XLogPageHeader pagehdr;
    7578             :     XLogRecPtr  startPos;
    7579             : 
    7580             :     /* sanity checks */
    7581          22 :     if (!RecoveryInProgress())
    7582           0 :         elog(ERROR, "can only be used at end of recovery");
    7583          22 :     if (pagePtr % XLOG_BLCKSZ != 0)
    7584           0 :         elog(ERROR, "invalid position for missing continuation record %X/%08X",
    7585             :              LSN_FORMAT_ARGS(pagePtr));
    7586             : 
    7587             :     /* The current WAL insert position should be right after the page header */
    7588          22 :     startPos = pagePtr;
    7589          22 :     if (XLogSegmentOffset(startPos, wal_segment_size) == 0)
    7590           2 :         startPos += SizeOfXLogLongPHD;
    7591             :     else
    7592          20 :         startPos += SizeOfXLogShortPHD;
    7593          22 :     recptr = GetXLogInsertRecPtr();
    7594          22 :     if (recptr != startPos)
    7595           0 :         elog(ERROR, "invalid WAL insert position %X/%08X for OVERWRITE_CONTRECORD",
    7596             :              LSN_FORMAT_ARGS(recptr));
    7597             : 
    7598          22 :     START_CRIT_SECTION();
    7599             : 
    7600             :     /*
    7601             :      * Initialize the XLOG page header (by GetXLogBuffer), and set the
    7602             :      * XLP_FIRST_IS_OVERWRITE_CONTRECORD flag.
    7603             :      *
    7604             :      * No other backend is allowed to write WAL yet, so acquiring the WAL
    7605             :      * insertion lock is just pro forma.
    7606             :      */
    7607          22 :     WALInsertLockAcquire();
    7608          22 :     pagehdr = (XLogPageHeader) GetXLogBuffer(pagePtr, newTLI);
    7609          22 :     pagehdr->xlp_info |= XLP_FIRST_IS_OVERWRITE_CONTRECORD;
    7610          22 :     WALInsertLockRelease();
    7611             : 
    7612             :     /*
    7613             :      * Insert the XLOG_OVERWRITE_CONTRECORD record as the first record on the
    7614             :      * page.  We know it becomes the first record, because no other backend is
    7615             :      * allowed to write WAL yet.
    7616             :      */
    7617          22 :     XLogBeginInsert();
    7618          22 :     xlrec.overwritten_lsn = aborted_lsn;
    7619          22 :     xlrec.overwrite_time = GetCurrentTimestamp();
    7620          22 :     XLogRegisterData(&xlrec, sizeof(xl_overwrite_contrecord));
    7621          22 :     recptr = XLogInsert(RM_XLOG_ID, XLOG_OVERWRITE_CONTRECORD);
    7622             : 
    7623             :     /* check that the record was inserted to the right place */
    7624          22 :     if (ProcLastRecPtr != startPos)
    7625           0 :         elog(ERROR, "OVERWRITE_CONTRECORD was inserted to unexpected position %X/%08X",
    7626             :              LSN_FORMAT_ARGS(ProcLastRecPtr));
    7627             : 
    7628          22 :     XLogFlush(recptr);
    7629             : 
    7630          22 :     END_CRIT_SECTION();
    7631             : 
    7632          22 :     return recptr;
    7633             : }
    7634             : 
    7635             : /*
    7636             :  * Flush all data in shared memory to disk, and fsync
    7637             :  *
    7638             :  * This is the common code shared between regular checkpoints and
    7639             :  * recovery restartpoints.
    7640             :  */
    7641             : static void
    7642        3550 : CheckPointGuts(XLogRecPtr checkPointRedo, int flags)
    7643             : {
    7644        3550 :     CheckPointRelationMap();
    7645        3550 :     CheckPointReplicationSlots(flags & CHECKPOINT_IS_SHUTDOWN);
    7646        3550 :     CheckPointSnapBuild();
    7647        3550 :     CheckPointLogicalRewriteHeap();
    7648        3550 :     CheckPointReplicationOrigin();
    7649             : 
    7650             :     /* Write out all dirty data in SLRUs and the main buffer pool */
    7651             :     TRACE_POSTGRESQL_BUFFER_CHECKPOINT_START(flags);
    7652        3550 :     CheckpointStats.ckpt_write_t = GetCurrentTimestamp();
    7653        3550 :     CheckPointCLOG();
    7654        3550 :     CheckPointCommitTs();
    7655        3550 :     CheckPointSUBTRANS();
    7656        3550 :     CheckPointMultiXact();
    7657        3550 :     CheckPointPredicate();
    7658        3550 :     CheckPointBuffers(flags);
    7659             : 
    7660             :     /* Perform all queued up fsyncs */
    7661             :     TRACE_POSTGRESQL_BUFFER_CHECKPOINT_SYNC_START();
    7662        3550 :     CheckpointStats.ckpt_sync_t = GetCurrentTimestamp();
    7663        3550 :     ProcessSyncRequests();
    7664        3550 :     CheckpointStats.ckpt_sync_end_t = GetCurrentTimestamp();
    7665             :     TRACE_POSTGRESQL_BUFFER_CHECKPOINT_DONE();
    7666             : 
    7667             :     /* We deliberately delay 2PC checkpointing as long as possible */
    7668        3550 :     CheckPointTwoPhase(checkPointRedo);
    7669        3550 : }
    7670             : 
    7671             : /*
    7672             :  * Save a checkpoint for recovery restart if appropriate
    7673             :  *
    7674             :  * This function is called each time a checkpoint record is read from XLOG.
    7675             :  * It must determine whether the checkpoint represents a safe restartpoint or
    7676             :  * not.  If so, the checkpoint record is stashed in shared memory so that
    7677             :  * CreateRestartPoint can consult it.  (Note that the latter function is
    7678             :  * executed by the checkpointer, while this one will be executed by the
    7679             :  * startup process.)
    7680             :  */
    7681             : static void
    7682        1454 : RecoveryRestartPoint(const CheckPoint *checkPoint, XLogReaderState *record)
    7683             : {
    7684             :     /*
    7685             :      * Also refrain from creating a restartpoint if we have seen any
    7686             :      * references to non-existent pages. Restarting recovery from the
    7687             :      * restartpoint would not see the references, so we would lose the
    7688             :      * cross-check that the pages belonged to a relation that was dropped
    7689             :      * later.
    7690             :      */
    7691        1454 :     if (XLogHaveInvalidPages())
    7692             :     {
    7693           0 :         elog(DEBUG2,
    7694             :              "could not record restart point at %X/%08X because there are unresolved references to invalid pages",
    7695             :              LSN_FORMAT_ARGS(checkPoint->redo));
    7696           0 :         return;
    7697             :     }
    7698             : 
    7699             :     /*
    7700             :      * Copy the checkpoint record to shared memory, so that checkpointer can
    7701             :      * work out the next time it wants to perform a restartpoint.
    7702             :      */
    7703        1454 :     SpinLockAcquire(&XLogCtl->info_lck);
    7704        1454 :     XLogCtl->lastCheckPointRecPtr = record->ReadRecPtr;
    7705        1454 :     XLogCtl->lastCheckPointEndPtr = record->EndRecPtr;
    7706        1454 :     XLogCtl->lastCheckPoint = *checkPoint;
    7707        1454 :     SpinLockRelease(&XLogCtl->info_lck);
    7708             : }
    7709             : 
    7710             : /*
    7711             :  * Establish a restartpoint if possible.
    7712             :  *
    7713             :  * This is similar to CreateCheckPoint, but is used during WAL recovery
    7714             :  * to establish a point from which recovery can roll forward without
    7715             :  * replaying the entire recovery log.
    7716             :  *
    7717             :  * Returns true if a new restartpoint was established. We can only establish
    7718             :  * a restartpoint if we have replayed a safe checkpoint record since last
    7719             :  * restartpoint.
    7720             :  */
    7721             : bool
    7722        1160 : CreateRestartPoint(int flags)
    7723             : {
    7724             :     XLogRecPtr  lastCheckPointRecPtr;
    7725             :     XLogRecPtr  lastCheckPointEndPtr;
    7726             :     CheckPoint  lastCheckPoint;
    7727             :     XLogRecPtr  PriorRedoPtr;
    7728             :     XLogRecPtr  receivePtr;
    7729             :     XLogRecPtr  replayPtr;
    7730             :     TimeLineID  replayTLI;
    7731             :     XLogRecPtr  endptr;
    7732             :     XLogSegNo   _logSegNo;
    7733             :     TimestampTz xtime;
    7734             : 
    7735             :     /* Concurrent checkpoint/restartpoint cannot happen */
    7736             :     Assert(!IsUnderPostmaster || MyBackendType == B_CHECKPOINTER);
    7737             : 
    7738             :     /* Get a local copy of the last safe checkpoint record. */
    7739        1160 :     SpinLockAcquire(&XLogCtl->info_lck);
    7740        1160 :     lastCheckPointRecPtr = XLogCtl->lastCheckPointRecPtr;
    7741        1160 :     lastCheckPointEndPtr = XLogCtl->lastCheckPointEndPtr;
    7742        1160 :     lastCheckPoint = XLogCtl->lastCheckPoint;
    7743        1160 :     SpinLockRelease(&XLogCtl->info_lck);
    7744             : 
    7745             :     /*
    7746             :      * Check that we're still in recovery mode. It's ok if we exit recovery
    7747             :      * mode after this check, the restart point is valid anyway.
    7748             :      */
    7749        1160 :     if (!RecoveryInProgress())
    7750             :     {
    7751           0 :         ereport(DEBUG2,
    7752             :                 (errmsg_internal("skipping restartpoint, recovery has already ended")));
    7753           0 :         return false;
    7754             :     }
    7755             : 
    7756             :     /*
    7757             :      * If the last checkpoint record we've replayed is already our last
    7758             :      * restartpoint, we can't perform a new restart point. We still update
    7759             :      * minRecoveryPoint in that case, so that if this is a shutdown restart
    7760             :      * point, we won't start up earlier than before. That's not strictly
    7761             :      * necessary, but when hot standby is enabled, it would be rather weird if
    7762             :      * the database opened up for read-only connections at a point-in-time
    7763             :      * before the last shutdown. Such time travel is still possible in case of
    7764             :      * immediate shutdown, though.
    7765             :      *
    7766             :      * We don't explicitly advance minRecoveryPoint when we do create a
    7767             :      * restartpoint. It's assumed that flushing the buffers will do that as a
    7768             :      * side-effect.
    7769             :      */
    7770        1160 :     if (!XLogRecPtrIsValid(lastCheckPointRecPtr) ||
    7771         494 :         lastCheckPoint.redo <= ControlFile->checkPointCopy.redo)
    7772             :     {
    7773         768 :         ereport(DEBUG2,
    7774             :                 errmsg_internal("skipping restartpoint, already performed at %X/%08X",
    7775             :                                 LSN_FORMAT_ARGS(lastCheckPoint.redo)));
    7776             : 
    7777         768 :         UpdateMinRecoveryPoint(InvalidXLogRecPtr, true);
    7778         768 :         if (flags & CHECKPOINT_IS_SHUTDOWN)
    7779             :         {
    7780          70 :             LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    7781          70 :             ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY;
    7782          70 :             UpdateControlFile();
    7783          70 :             LWLockRelease(ControlFileLock);
    7784             :         }
    7785         768 :         return false;
    7786             :     }
    7787             : 
    7788             :     /*
    7789             :      * Update the shared RedoRecPtr so that the startup process can calculate
    7790             :      * the number of segments replayed since last restartpoint, and request a
    7791             :      * restartpoint if it exceeds CheckPointSegments.
    7792             :      *
    7793             :      * Like in CreateCheckPoint(), hold off insertions to update it, although
    7794             :      * during recovery this is just pro forma, because no WAL insertions are
    7795             :      * happening.
    7796             :      */
    7797         392 :     WALInsertLockAcquireExclusive();
    7798         392 :     RedoRecPtr = XLogCtl->Insert.RedoRecPtr = lastCheckPoint.redo;
    7799         392 :     WALInsertLockRelease();
    7800             : 
    7801             :     /* Also update the info_lck-protected copy */
    7802         392 :     SpinLockAcquire(&XLogCtl->info_lck);
    7803         392 :     XLogCtl->RedoRecPtr = lastCheckPoint.redo;
    7804         392 :     SpinLockRelease(&XLogCtl->info_lck);
    7805             : 
    7806             :     /*
    7807             :      * Prepare to accumulate statistics.
    7808             :      *
    7809             :      * Note: because it is possible for log_checkpoints to change while a
    7810             :      * checkpoint proceeds, we always accumulate stats, even if
    7811             :      * log_checkpoints is currently off.
    7812             :      */
    7813        4312 :     MemSet(&CheckpointStats, 0, sizeof(CheckpointStats));
    7814         392 :     CheckpointStats.ckpt_start_t = GetCurrentTimestamp();
    7815             : 
    7816         392 :     if (log_checkpoints)
    7817         392 :         LogCheckpointStart(flags, true);
    7818             : 
    7819             :     /* Update the process title */
    7820         392 :     update_checkpoint_display(flags, true, false);
    7821             : 
    7822         392 :     CheckPointGuts(lastCheckPoint.redo, flags);
    7823             : 
    7824             :     /*
    7825             :      * This location needs to be after CheckPointGuts() to ensure that some
    7826             :      * work has already happened during this checkpoint.
    7827             :      */
    7828         392 :     INJECTION_POINT("create-restart-point", NULL);
    7829             : 
    7830             :     /*
    7831             :      * Remember the prior checkpoint's redo ptr for
    7832             :      * UpdateCheckPointDistanceEstimate()
    7833             :      */
    7834         392 :     PriorRedoPtr = ControlFile->checkPointCopy.redo;
    7835             : 
    7836             :     /*
    7837             :      * Update pg_control, using current time.  Check that it still shows an
    7838             :      * older checkpoint, else do nothing; this is a quick hack to make sure
    7839             :      * nothing really bad happens if somehow we get here after the
    7840             :      * end-of-recovery checkpoint.
    7841             :      */
    7842         392 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    7843         392 :     if (ControlFile->checkPointCopy.redo < lastCheckPoint.redo)
    7844             :     {
    7845             :         /*
    7846             :          * Update the checkpoint information.  We do this even if the cluster
    7847             :          * does not show DB_IN_ARCHIVE_RECOVERY to match with the set of WAL
    7848             :          * segments recycled below.
    7849             :          */
    7850         392 :         ControlFile->checkPoint = lastCheckPointRecPtr;
    7851         392 :         ControlFile->checkPointCopy = lastCheckPoint;
    7852             : 
    7853             :         /*
    7854             :          * Ensure minRecoveryPoint is past the checkpoint record and update it
    7855             :          * if the control file still shows DB_IN_ARCHIVE_RECOVERY.  Normally,
    7856             :          * this will have happened already while writing out dirty buffers,
    7857             :          * but not necessarily - e.g. because no buffers were dirtied.  We do
    7858             :          * this because a backup performed in recovery uses minRecoveryPoint
    7859             :          * to determine which WAL files must be included in the backup, and
    7860             :          * the file (or files) containing the checkpoint record must be
    7861             :          * included, at a minimum.  Note that for an ordinary restart of
    7862             :          * recovery there's no value in having the minimum recovery point any
    7863             :          * earlier than this anyway, because redo will begin just after the
    7864             :          * checkpoint record.
    7865             :          */
    7866         392 :         if (ControlFile->state == DB_IN_ARCHIVE_RECOVERY)
    7867             :         {
    7868         392 :             if (ControlFile->minRecoveryPoint < lastCheckPointEndPtr)
    7869             :             {
    7870          40 :                 ControlFile->minRecoveryPoint = lastCheckPointEndPtr;
    7871          40 :                 ControlFile->minRecoveryPointTLI = lastCheckPoint.ThisTimeLineID;
    7872             : 
    7873             :                 /* update local copy */
    7874          40 :                 LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
    7875          40 :                 LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
    7876             :             }
    7877         392 :             if (flags & CHECKPOINT_IS_SHUTDOWN)
    7878          44 :                 ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY;
    7879             :         }
    7880         392 :         UpdateControlFile();
    7881             :     }
    7882         392 :     LWLockRelease(ControlFileLock);
    7883             : 
    7884             :     /*
    7885             :      * Update the average distance between checkpoints/restartpoints if the
    7886             :      * prior checkpoint exists.
    7887             :      */
    7888         392 :     if (XLogRecPtrIsValid(PriorRedoPtr))
    7889         392 :         UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
    7890             : 
    7891             :     /*
    7892             :      * Delete old log files, those no longer needed for last restartpoint to
    7893             :      * prevent the disk holding the xlog from growing full.
    7894             :      */
    7895         392 :     XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
    7896             : 
    7897             :     /*
    7898             :      * Retreat _logSegNo using the current end of xlog replayed or received,
    7899             :      * whichever is later.
    7900             :      */
    7901         392 :     receivePtr = GetWalRcvFlushRecPtr(NULL, NULL);
    7902         392 :     replayPtr = GetXLogReplayRecPtr(&replayTLI);
    7903         392 :     endptr = (receivePtr < replayPtr) ? replayPtr : receivePtr;
    7904         392 :     KeepLogSeg(endptr, &_logSegNo);
    7905         392 :     if (InvalidateObsoleteReplicationSlots(RS_INVAL_WAL_REMOVED | RS_INVAL_IDLE_TIMEOUT,
    7906             :                                            _logSegNo, InvalidOid,
    7907             :                                            InvalidTransactionId))
    7908             :     {
    7909             :         /*
    7910             :          * Some slots have been invalidated; recalculate the old-segment
    7911             :          * horizon, starting again from RedoRecPtr.
    7912             :          */
    7913           2 :         XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
    7914           2 :         KeepLogSeg(endptr, &_logSegNo);
    7915             :     }
    7916         392 :     _logSegNo--;
    7917             : 
    7918             :     /*
    7919             :      * Try to recycle segments on a useful timeline. If we've been promoted
    7920             :      * since the beginning of this restartpoint, use the new timeline chosen
    7921             :      * at end of recovery.  If we're still in recovery, use the timeline we're
    7922             :      * currently replaying.
    7923             :      *
    7924             :      * There is no guarantee that the WAL segments will be useful on the
    7925             :      * current timeline; if recovery proceeds to a new timeline right after
    7926             :      * this, the pre-allocated WAL segments on this timeline will not be used,
    7927             :      * and will go wasted until recycled on the next restartpoint. We'll live
    7928             :      * with that.
    7929             :      */
    7930         392 :     if (!RecoveryInProgress())
    7931           0 :         replayTLI = XLogCtl->InsertTimeLineID;
    7932             : 
    7933         392 :     RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr, replayTLI);
    7934             : 
    7935             :     /*
    7936             :      * Make more log segments if needed.  (Do this after recycling old log
    7937             :      * segments, since that may supply some of the needed files.)
    7938             :      */
    7939         392 :     PreallocXlogFiles(endptr, replayTLI);
    7940             : 
    7941             :     /*
    7942             :      * Truncate pg_subtrans if possible.  We can throw away all data before
    7943             :      * the oldest XMIN of any running transaction.  No future transaction will
    7944             :      * attempt to reference any pg_subtrans entry older than that (see Asserts
    7945             :      * in subtrans.c).  When hot standby is disabled, though, we mustn't do
    7946             :      * this because StartupSUBTRANS hasn't been called yet.
    7947             :      */
    7948         392 :     if (EnableHotStandby)
    7949         392 :         TruncateSUBTRANS(GetOldestTransactionIdConsideredRunning());
    7950             : 
    7951             :     /* Real work is done; log and update stats. */
    7952         392 :     LogCheckpointEnd(true);
    7953             : 
    7954             :     /* Reset the process title */
    7955         392 :     update_checkpoint_display(flags, true, true);
    7956             : 
    7957         392 :     xtime = GetLatestXTime();
    7958         392 :     ereport((log_checkpoints ? LOG : DEBUG2),
    7959             :             errmsg("recovery restart point at %X/%08X",
    7960             :                    LSN_FORMAT_ARGS(lastCheckPoint.redo)),
    7961             :             xtime ? errdetail("Last completed transaction was at log time %s.",
    7962             :                               timestamptz_to_str(xtime)) : 0);
    7963             : 
    7964             :     /*
    7965             :      * Finally, execute archive_cleanup_command, if any.
    7966             :      */
    7967         392 :     if (archiveCleanupCommand && strcmp(archiveCleanupCommand, "") != 0)
    7968           0 :         ExecuteRecoveryCommand(archiveCleanupCommand,
    7969             :                                "archive_cleanup_command",
    7970             :                                false,
    7971             :                                WAIT_EVENT_ARCHIVE_CLEANUP_COMMAND);
    7972             : 
    7973         392 :     return true;
    7974             : }
    7975             : 
    7976             : /*
    7977             :  * Report availability of WAL for the given target LSN
    7978             :  *      (typically a slot's restart_lsn)
    7979             :  *
    7980             :  * Returns one of the following enum values:
    7981             :  *
    7982             :  * * WALAVAIL_RESERVED means targetLSN is available and it is in the range of
    7983             :  *   max_wal_size.
    7984             :  *
    7985             :  * * WALAVAIL_EXTENDED means it is still available by preserving extra
    7986             :  *   segments beyond max_wal_size. If max_slot_wal_keep_size is smaller
    7987             :  *   than max_wal_size, this state is not returned.
    7988             :  *
    7989             :  * * WALAVAIL_UNRESERVED means it is being lost and the next checkpoint will
    7990             :  *   remove reserved segments. The walsender using this slot may return to the
    7991             :  *   above.
    7992             :  *
    7993             :  * * WALAVAIL_REMOVED means it has been removed. A replication stream on
    7994             :  *   a slot with this LSN cannot continue.  (Any associated walsender
    7995             :  *   processes should have been terminated already.)
    7996             :  *
    7997             :  * * WALAVAIL_INVALID_LSN means the slot hasn't been set to reserve WAL.
    7998             :  */
    7999             : WALAvailability
    8000        1088 : GetWALAvailability(XLogRecPtr targetLSN)
    8001             : {
    8002             :     XLogRecPtr  currpos;        /* current write LSN */
    8003             :     XLogSegNo   currSeg;        /* segid of currpos */
    8004             :     XLogSegNo   targetSeg;      /* segid of targetLSN */
    8005             :     XLogSegNo   oldestSeg;      /* actual oldest segid */
    8006             :     XLogSegNo   oldestSegMaxWalSize;    /* oldest segid kept by max_wal_size */
    8007             :     XLogSegNo   oldestSlotSeg;  /* oldest segid kept by slot */
    8008             :     uint64      keepSegs;
    8009             : 
    8010             :     /*
    8011             :      * slot does not reserve WAL. Either deactivated, or has never been active
    8012             :      */
    8013        1088 :     if (!XLogRecPtrIsValid(targetLSN))
    8014          78 :         return WALAVAIL_INVALID_LSN;
    8015             : 
    8016             :     /*
    8017             :      * Calculate the oldest segment currently reserved by all slots,
    8018             :      * considering wal_keep_size and max_slot_wal_keep_size.  Initialize
    8019             :      * oldestSlotSeg to the current segment.
    8020             :      */
    8021        1010 :     currpos = GetXLogWriteRecPtr();
    8022        1010 :     XLByteToSeg(currpos, oldestSlotSeg, wal_segment_size);
    8023        1010 :     KeepLogSeg(currpos, &oldestSlotSeg);
    8024             : 
    8025             :     /*
    8026             :      * Find the oldest extant segment file. We get 1 until checkpoint removes
    8027             :      * the first WAL segment file since startup, which causes the status being
    8028             :      * wrong under certain abnormal conditions but that doesn't actually harm.
    8029             :      */
    8030        1010 :     oldestSeg = XLogGetLastRemovedSegno() + 1;
    8031             : 
    8032             :     /* calculate oldest segment by max_wal_size */
    8033        1010 :     XLByteToSeg(currpos, currSeg, wal_segment_size);
    8034        1010 :     keepSegs = ConvertToXSegs(max_wal_size_mb, wal_segment_size) + 1;
    8035             : 
    8036        1010 :     if (currSeg > keepSegs)
    8037          16 :         oldestSegMaxWalSize = currSeg - keepSegs;
    8038             :     else
    8039         994 :         oldestSegMaxWalSize = 1;
    8040             : 
    8041             :     /* the segment we care about */
    8042        1010 :     XLByteToSeg(targetLSN, targetSeg, wal_segment_size);
    8043             : 
    8044             :     /*
    8045             :      * No point in returning reserved or extended status values if the
    8046             :      * targetSeg is known to be lost.
    8047             :      */
    8048        1010 :     if (targetSeg >= oldestSlotSeg)
    8049             :     {
    8050             :         /* show "reserved" when targetSeg is within max_wal_size */
    8051        1008 :         if (targetSeg >= oldestSegMaxWalSize)
    8052        1004 :             return WALAVAIL_RESERVED;
    8053             : 
    8054             :         /* being retained by slots exceeding max_wal_size */
    8055           4 :         return WALAVAIL_EXTENDED;
    8056             :     }
    8057             : 
    8058             :     /* WAL segments are no longer retained but haven't been removed yet */
    8059           2 :     if (targetSeg >= oldestSeg)
    8060           2 :         return WALAVAIL_UNRESERVED;
    8061             : 
    8062             :     /* Definitely lost */
    8063           0 :     return WALAVAIL_REMOVED;
    8064             : }
    8065             : 
    8066             : 
    8067             : /*
    8068             :  * Retreat *logSegNo to the last segment that we need to retain because of
    8069             :  * either wal_keep_size or replication slots.
    8070             :  *
    8071             :  * This is calculated by subtracting wal_keep_size from the given xlog
    8072             :  * location, recptr and by making sure that that result is below the
    8073             :  * requirement of replication slots.  For the latter criterion we do consider
    8074             :  * the effects of max_slot_wal_keep_size: reserve at most that much space back
    8075             :  * from recptr.
    8076             :  *
    8077             :  * Note about replication slots: if this function calculates a value
    8078             :  * that's further ahead than what slots need reserved, then affected
    8079             :  * slots need to be invalidated and this function invoked again.
    8080             :  * XXX it might be a good idea to rewrite this function so that
    8081             :  * invalidation is optionally done here, instead.
    8082             :  */
    8083             : static void
    8084        4570 : KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
    8085             : {
    8086             :     XLogSegNo   currSegNo;
    8087             :     XLogSegNo   segno;
    8088             :     XLogRecPtr  keep;
    8089             : 
    8090        4570 :     XLByteToSeg(recptr, currSegNo, wal_segment_size);
    8091        4570 :     segno = currSegNo;
    8092             : 
    8093             :     /* Calculate how many segments are kept by slots. */
    8094        4570 :     keep = XLogGetReplicationSlotMinimumLSN();
    8095        4570 :     if (XLogRecPtrIsValid(keep) && keep < recptr)
    8096             :     {
    8097        1324 :         XLByteToSeg(keep, segno, wal_segment_size);
    8098             : 
    8099             :         /*
    8100             :          * Account for max_slot_wal_keep_size to avoid keeping more than
    8101             :          * configured.  However, don't do that during a binary upgrade: if
    8102             :          * slots were to be invalidated because of this, it would not be
    8103             :          * possible to preserve logical ones during the upgrade.
    8104             :          */
    8105        1324 :         if (max_slot_wal_keep_size_mb >= 0 && !IsBinaryUpgrade)
    8106             :         {
    8107             :             uint64      slot_keep_segs;
    8108             : 
    8109          46 :             slot_keep_segs =
    8110          46 :                 ConvertToXSegs(max_slot_wal_keep_size_mb, wal_segment_size);
    8111             : 
    8112          46 :             if (currSegNo - segno > slot_keep_segs)
    8113          12 :                 segno = currSegNo - slot_keep_segs;
    8114             :         }
    8115             :     }
    8116             : 
    8117             :     /*
    8118             :      * If WAL summarization is in use, don't remove WAL that has yet to be
    8119             :      * summarized.
    8120             :      */
    8121        4570 :     keep = GetOldestUnsummarizedLSN(NULL, NULL);
    8122        4570 :     if (XLogRecPtrIsValid(keep))
    8123             :     {
    8124             :         XLogSegNo   unsummarized_segno;
    8125             : 
    8126           4 :         XLByteToSeg(keep, unsummarized_segno, wal_segment_size);
    8127           4 :         if (unsummarized_segno < segno)
    8128           2 :             segno = unsummarized_segno;
    8129             :     }
    8130             : 
    8131             :     /* but, keep at least wal_keep_size if that's set */
    8132        4570 :     if (wal_keep_size_mb > 0)
    8133             :     {
    8134             :         uint64      keep_segs;
    8135             : 
    8136         148 :         keep_segs = ConvertToXSegs(wal_keep_size_mb, wal_segment_size);
    8137         148 :         if (currSegNo - segno < keep_segs)
    8138             :         {
    8139             :             /* avoid underflow, don't go below 1 */
    8140         148 :             if (currSegNo <= keep_segs)
    8141         140 :                 segno = 1;
    8142             :             else
    8143           8 :                 segno = currSegNo - keep_segs;
    8144             :         }
    8145             :     }
    8146             : 
    8147             :     /* don't delete WAL segments newer than the calculated segment */
    8148        4570 :     if (segno < *logSegNo)
    8149         762 :         *logSegNo = segno;
    8150        4570 : }
    8151             : 
    8152             : /*
    8153             :  * Write a NEXTOID log record
    8154             :  */
    8155             : void
    8156        1262 : XLogPutNextOid(Oid nextOid)
    8157             : {
    8158        1262 :     XLogBeginInsert();
    8159        1262 :     XLogRegisterData(&nextOid, sizeof(Oid));
    8160        1262 :     (void) XLogInsert(RM_XLOG_ID, XLOG_NEXTOID);
    8161             : 
    8162             :     /*
    8163             :      * We need not flush the NEXTOID record immediately, because any of the
    8164             :      * just-allocated OIDs could only reach disk as part of a tuple insert or
    8165             :      * update that would have its own XLOG record that must follow the NEXTOID
    8166             :      * record.  Therefore, the standard buffer LSN interlock applied to those
    8167             :      * records will ensure no such OID reaches disk before the NEXTOID record
    8168             :      * does.
    8169             :      *
    8170             :      * Note, however, that the above statement only covers state "within" the
    8171             :      * database.  When we use a generated OID as a file or directory name, we
    8172             :      * are in a sense violating the basic WAL rule, because that filesystem
    8173             :      * change may reach disk before the NEXTOID WAL record does.  The impact
    8174             :      * of this is that if a database crash occurs immediately afterward, we
    8175             :      * might after restart re-generate the same OID and find that it conflicts
    8176             :      * with the leftover file or directory.  But since for safety's sake we
    8177             :      * always loop until finding a nonconflicting filename, this poses no real
    8178             :      * problem in practice. See pgsql-hackers discussion 27-Sep-2006.
    8179             :      */
    8180        1262 : }
    8181             : 
    8182             : /*
    8183             :  * Write an XLOG SWITCH record.
    8184             :  *
    8185             :  * Here we just blindly issue an XLogInsert request for the record.
    8186             :  * All the magic happens inside XLogInsert.
    8187             :  *
    8188             :  * The return value is either the end+1 address of the switch record,
    8189             :  * or the end+1 address of the prior segment if we did not need to
    8190             :  * write a switch record because we are already at segment start.
    8191             :  */
    8192             : XLogRecPtr
    8193        1576 : RequestXLogSwitch(bool mark_unimportant)
    8194             : {
    8195             :     XLogRecPtr  RecPtr;
    8196             : 
    8197             :     /* XLOG SWITCH has no data */
    8198        1576 :     XLogBeginInsert();
    8199             : 
    8200        1576 :     if (mark_unimportant)
    8201           0 :         XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT);
    8202        1576 :     RecPtr = XLogInsert(RM_XLOG_ID, XLOG_SWITCH);
    8203             : 
    8204        1576 :     return RecPtr;
    8205             : }
    8206             : 
    8207             : /*
    8208             :  * Write a RESTORE POINT record
    8209             :  */
    8210             : XLogRecPtr
    8211           6 : XLogRestorePoint(const char *rpName)
    8212             : {
    8213             :     XLogRecPtr  RecPtr;
    8214             :     xl_restore_point xlrec;
    8215             : 
    8216           6 :     xlrec.rp_time = GetCurrentTimestamp();
    8217           6 :     strlcpy(xlrec.rp_name, rpName, MAXFNAMELEN);
    8218             : 
    8219           6 :     XLogBeginInsert();
    8220           6 :     XLogRegisterData(&xlrec, sizeof(xl_restore_point));
    8221             : 
    8222           6 :     RecPtr = XLogInsert(RM_XLOG_ID, XLOG_RESTORE_POINT);
    8223             : 
    8224           6 :     ereport(LOG,
    8225             :             errmsg("restore point \"%s\" created at %X/%08X",
    8226             :                    rpName, LSN_FORMAT_ARGS(RecPtr)));
    8227             : 
    8228           6 :     return RecPtr;
    8229             : }
    8230             : 
    8231             : /*
    8232             :  * Check if any of the GUC parameters that are critical for hot standby
    8233             :  * have changed, and update the value in pg_control file if necessary.
    8234             :  */
    8235             : static void
    8236        1856 : XLogReportParameters(void)
    8237             : {
    8238        1856 :     if (wal_level != ControlFile->wal_level ||
    8239        1372 :         wal_log_hints != ControlFile->wal_log_hints ||
    8240        1200 :         MaxConnections != ControlFile->MaxConnections ||
    8241        1198 :         max_worker_processes != ControlFile->max_worker_processes ||
    8242        1192 :         max_wal_senders != ControlFile->max_wal_senders ||
    8243        1142 :         max_prepared_xacts != ControlFile->max_prepared_xacts ||
    8244         944 :         max_locks_per_xact != ControlFile->max_locks_per_xact ||
    8245         944 :         track_commit_timestamp != ControlFile->track_commit_timestamp)
    8246             :     {
    8247             :         /*
    8248             :          * The change in number of backend slots doesn't need to be WAL-logged
    8249             :          * if archiving is not enabled, as you can't start archive recovery
    8250             :          * with wal_level=minimal anyway. We don't really care about the
    8251             :          * values in pg_control either if wal_level=minimal, but seems better
    8252             :          * to keep them up-to-date to avoid confusion.
    8253             :          */
    8254         936 :         if (wal_level != ControlFile->wal_level || XLogIsNeeded())
    8255             :         {
    8256             :             xl_parameter_change xlrec;
    8257             :             XLogRecPtr  recptr;
    8258             : 
    8259         886 :             xlrec.MaxConnections = MaxConnections;
    8260         886 :             xlrec.max_worker_processes = max_worker_processes;
    8261         886 :             xlrec.max_wal_senders = max_wal_senders;
    8262         886 :             xlrec.max_prepared_xacts = max_prepared_xacts;
    8263         886 :             xlrec.max_locks_per_xact = max_locks_per_xact;
    8264         886 :             xlrec.wal_level = wal_level;
    8265         886 :             xlrec.wal_log_hints = wal_log_hints;
    8266         886 :             xlrec.track_commit_timestamp = track_commit_timestamp;
    8267             : 
    8268         886 :             XLogBeginInsert();
    8269         886 :             XLogRegisterData(&xlrec, sizeof(xlrec));
    8270             : 
    8271         886 :             recptr = XLogInsert(RM_XLOG_ID, XLOG_PARAMETER_CHANGE);
    8272         886 :             XLogFlush(recptr);
    8273             :         }
    8274             : 
    8275         936 :         LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    8276             : 
    8277         936 :         ControlFile->MaxConnections = MaxConnections;
    8278         936 :         ControlFile->max_worker_processes = max_worker_processes;
    8279         936 :         ControlFile->max_wal_senders = max_wal_senders;
    8280         936 :         ControlFile->max_prepared_xacts = max_prepared_xacts;
    8281         936 :         ControlFile->max_locks_per_xact = max_locks_per_xact;
    8282         936 :         ControlFile->wal_level = wal_level;
    8283         936 :         ControlFile->wal_log_hints = wal_log_hints;
    8284         936 :         ControlFile->track_commit_timestamp = track_commit_timestamp;
    8285         936 :         UpdateControlFile();
    8286             : 
    8287         936 :         LWLockRelease(ControlFileLock);
    8288             :     }
    8289        1856 : }
    8290             : 
    8291             : /*
    8292             :  * Update full_page_writes in shared memory, and write an
    8293             :  * XLOG_FPW_CHANGE record if necessary.
    8294             :  *
    8295             :  * Note: this function assumes there is no other process running
    8296             :  * concurrently that could update it.
    8297             :  */
    8298             : void
    8299        3124 : UpdateFullPageWrites(void)
    8300             : {
    8301        3124 :     XLogCtlInsert *Insert = &XLogCtl->Insert;
    8302             :     bool        recoveryInProgress;
    8303             : 
    8304             :     /*
    8305             :      * Do nothing if full_page_writes has not been changed.
    8306             :      *
    8307             :      * It's safe to check the shared full_page_writes without the lock,
    8308             :      * because we assume that there is no concurrently running process which
    8309             :      * can update it.
    8310             :      */
    8311        3124 :     if (fullPageWrites == Insert->fullPageWrites)
    8312        2326 :         return;
    8313             : 
    8314             :     /*
    8315             :      * Perform this outside critical section so that the WAL insert
    8316             :      * initialization done by RecoveryInProgress() doesn't trigger an
    8317             :      * assertion failure.
    8318             :      */
    8319         798 :     recoveryInProgress = RecoveryInProgress();
    8320             : 
    8321         798 :     START_CRIT_SECTION();
    8322             : 
    8323             :     /*
    8324             :      * It's always safe to take full page images, even when not strictly
    8325             :      * required, but not the other round. So if we're setting full_page_writes
    8326             :      * to true, first set it true and then write the WAL record. If we're
    8327             :      * setting it to false, first write the WAL record and then set the global
    8328             :      * flag.
    8329             :      */
    8330         798 :     if (fullPageWrites)
    8331             :     {
    8332         776 :         WALInsertLockAcquireExclusive();
    8333         776 :         Insert->fullPageWrites = true;
    8334         776 :         WALInsertLockRelease();
    8335             :     }
    8336             : 
    8337             :     /*
    8338             :      * Write an XLOG_FPW_CHANGE record. This allows us to keep track of
    8339             :      * full_page_writes during archive recovery, if required.
    8340             :      */
    8341         798 :     if (XLogStandbyInfoActive() && !recoveryInProgress)
    8342             :     {
    8343           0 :         XLogBeginInsert();
    8344           0 :         XLogRegisterData(&fullPageWrites, sizeof(bool));
    8345             : 
    8346           0 :         XLogInsert(RM_XLOG_ID, XLOG_FPW_CHANGE);
    8347             :     }
    8348             : 
    8349         798 :     if (!fullPageWrites)
    8350             :     {
    8351          22 :         WALInsertLockAcquireExclusive();
    8352          22 :         Insert->fullPageWrites = false;
    8353          22 :         WALInsertLockRelease();
    8354             :     }
    8355         798 :     END_CRIT_SECTION();
    8356             : }
    8357             : 
    8358             : /*
    8359             :  * XLOG resource manager's routines
    8360             :  *
    8361             :  * Definitions of info values are in include/catalog/pg_control.h, though
    8362             :  * not all record types are related to control file updates.
    8363             :  *
    8364             :  * NOTE: Some XLOG record types that are directly related to WAL recovery
    8365             :  * are handled in xlogrecovery_redo().
    8366             :  */
    8367             : void
    8368       88048 : xlog_redo(XLogReaderState *record)
    8369             : {
    8370       88048 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
    8371       88048 :     XLogRecPtr  lsn = record->EndRecPtr;
    8372             : 
    8373             :     /*
    8374             :      * In XLOG rmgr, backup blocks are only used by XLOG_FPI and
    8375             :      * XLOG_FPI_FOR_HINT records.
    8376             :      */
    8377             :     Assert(info == XLOG_FPI || info == XLOG_FPI_FOR_HINT ||
    8378             :            !XLogRecHasAnyBlockRefs(record));
    8379             : 
    8380       88048 :     if (info == XLOG_NEXTOID)
    8381             :     {
    8382             :         Oid         nextOid;
    8383             : 
    8384             :         /*
    8385             :          * We used to try to take the maximum of TransamVariables->nextOid and
    8386             :          * the recorded nextOid, but that fails if the OID counter wraps
    8387             :          * around.  Since no OID allocation should be happening during replay
    8388             :          * anyway, better to just believe the record exactly.  We still take
    8389             :          * OidGenLock while setting the variable, just in case.
    8390             :          */
    8391         192 :         memcpy(&nextOid, XLogRecGetData(record), sizeof(Oid));
    8392         192 :         LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
    8393         192 :         TransamVariables->nextOid = nextOid;
    8394         192 :         TransamVariables->oidCount = 0;
    8395         192 :         LWLockRelease(OidGenLock);
    8396             :     }
    8397       87856 :     else if (info == XLOG_CHECKPOINT_SHUTDOWN)
    8398             :     {
    8399             :         CheckPoint  checkPoint;
    8400             :         TimeLineID  replayTLI;
    8401             : 
    8402          78 :         memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
    8403             :         /* In a SHUTDOWN checkpoint, believe the counters exactly */
    8404          78 :         LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
    8405          78 :         TransamVariables->nextXid = checkPoint.nextXid;
    8406          78 :         LWLockRelease(XidGenLock);
    8407          78 :         LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
    8408          78 :         TransamVariables->nextOid = checkPoint.nextOid;
    8409          78 :         TransamVariables->oidCount = 0;
    8410          78 :         LWLockRelease(OidGenLock);
    8411          78 :         MultiXactSetNextMXact(checkPoint.nextMulti,
    8412             :                               checkPoint.nextMultiOffset);
    8413             : 
    8414          78 :         MultiXactAdvanceOldest(checkPoint.oldestMulti,
    8415             :                                checkPoint.oldestMultiDB);
    8416             : 
    8417             :         /*
    8418             :          * No need to set oldestClogXid here as well; it'll be set when we
    8419             :          * redo an xl_clog_truncate if it changed since initialization.
    8420             :          */
    8421          78 :         SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
    8422             : 
    8423             :         /*
    8424             :          * If we see a shutdown checkpoint while waiting for an end-of-backup
    8425             :          * record, the backup was canceled and the end-of-backup record will
    8426             :          * never arrive.
    8427             :          */
    8428          78 :         if (ArchiveRecoveryRequested &&
    8429          76 :             XLogRecPtrIsValid(ControlFile->backupStartPoint) &&
    8430           0 :             !XLogRecPtrIsValid(ControlFile->backupEndPoint))
    8431           0 :             ereport(PANIC,
    8432             :                     (errmsg("online backup was canceled, recovery cannot continue")));
    8433             : 
    8434             :         /*
    8435             :          * If we see a shutdown checkpoint, we know that nothing was running
    8436             :          * on the primary at this point. So fake-up an empty running-xacts
    8437             :          * record and use that here and now. Recover additional standby state
    8438             :          * for prepared transactions.
    8439             :          */
    8440          78 :         if (standbyState >= STANDBY_INITIALIZED)
    8441             :         {
    8442             :             TransactionId *xids;
    8443             :             int         nxids;
    8444             :             TransactionId oldestActiveXID;
    8445             :             TransactionId latestCompletedXid;
    8446             :             RunningTransactionsData running;
    8447             : 
    8448          72 :             oldestActiveXID = PrescanPreparedTransactions(&xids, &nxids);
    8449             : 
    8450             :             /* Update pg_subtrans entries for any prepared transactions */
    8451          72 :             StandbyRecoverPreparedTransactions();
    8452             : 
    8453             :             /*
    8454             :              * Construct a RunningTransactions snapshot representing a shut
    8455             :              * down server, with only prepared transactions still alive. We're
    8456             :              * never overflowed at this point because all subxids are listed
    8457             :              * with their parent prepared transactions.
    8458             :              */
    8459          72 :             running.xcnt = nxids;
    8460          72 :             running.subxcnt = 0;
    8461          72 :             running.subxid_status = SUBXIDS_IN_SUBTRANS;
    8462          72 :             running.nextXid = XidFromFullTransactionId(checkPoint.nextXid);
    8463          72 :             running.oldestRunningXid = oldestActiveXID;
    8464          72 :             latestCompletedXid = XidFromFullTransactionId(checkPoint.nextXid);
    8465          72 :             TransactionIdRetreat(latestCompletedXid);
    8466             :             Assert(TransactionIdIsNormal(latestCompletedXid));
    8467          72 :             running.latestCompletedXid = latestCompletedXid;
    8468          72 :             running.xids = xids;
    8469             : 
    8470          72 :             ProcArrayApplyRecoveryInfo(&running);
    8471             :         }
    8472             : 
    8473             :         /* ControlFile->checkPointCopy always tracks the latest ckpt XID */
    8474          78 :         LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    8475          78 :         ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
    8476          78 :         LWLockRelease(ControlFileLock);
    8477             : 
    8478             :         /*
    8479             :          * We should've already switched to the new TLI before replaying this
    8480             :          * record.
    8481             :          */
    8482          78 :         (void) GetCurrentReplayRecPtr(&replayTLI);
    8483          78 :         if (checkPoint.ThisTimeLineID != replayTLI)
    8484           0 :             ereport(PANIC,
    8485             :                     (errmsg("unexpected timeline ID %u (should be %u) in shutdown checkpoint record",
    8486             :                             checkPoint.ThisTimeLineID, replayTLI)));
    8487             : 
    8488          78 :         RecoveryRestartPoint(&checkPoint, record);
    8489             : 
    8490             :         /*
    8491             :          * After replaying a checkpoint record, free all smgr objects.
    8492             :          * Otherwise we would never do so for dropped relations, as the
    8493             :          * startup does not process shared invalidation messages or call
    8494             :          * AtEOXact_SMgr().
    8495             :          */
    8496          78 :         smgrdestroyall();
    8497             :     }
    8498       87778 :     else if (info == XLOG_CHECKPOINT_ONLINE)
    8499             :     {
    8500             :         CheckPoint  checkPoint;
    8501             :         TimeLineID  replayTLI;
    8502             : 
    8503        1376 :         memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
    8504             :         /* In an ONLINE checkpoint, treat the XID counter as a minimum */
    8505        1376 :         LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
    8506        1376 :         if (FullTransactionIdPrecedes(TransamVariables->nextXid,
    8507             :                                       checkPoint.nextXid))
    8508           0 :             TransamVariables->nextXid = checkPoint.nextXid;
    8509        1376 :         LWLockRelease(XidGenLock);
    8510             : 
    8511             :         /*
    8512             :          * We ignore the nextOid counter in an ONLINE checkpoint, preferring
    8513             :          * to track OID assignment through XLOG_NEXTOID records.  The nextOid
    8514             :          * counter is from the start of the checkpoint and might well be stale
    8515             :          * compared to later XLOG_NEXTOID records.  We could try to take the
    8516             :          * maximum of the nextOid counter and our latest value, but since
    8517             :          * there's no particular guarantee about the speed with which the OID
    8518             :          * counter wraps around, that's a risky thing to do.  In any case,
    8519             :          * users of the nextOid counter are required to avoid assignment of
    8520             :          * duplicates, so that a somewhat out-of-date value should be safe.
    8521             :          */
    8522             : 
    8523             :         /* Handle multixact */
    8524        1376 :         MultiXactAdvanceNextMXact(checkPoint.nextMulti,
    8525             :                                   checkPoint.nextMultiOffset);
    8526             : 
    8527             :         /*
    8528             :          * NB: This may perform multixact truncation when replaying WAL
    8529             :          * generated by an older primary.
    8530             :          */
    8531        1376 :         MultiXactAdvanceOldest(checkPoint.oldestMulti,
    8532             :                                checkPoint.oldestMultiDB);
    8533        1376 :         if (TransactionIdPrecedes(TransamVariables->oldestXid,
    8534             :                                   checkPoint.oldestXid))
    8535           0 :             SetTransactionIdLimit(checkPoint.oldestXid,
    8536             :                                   checkPoint.oldestXidDB);
    8537             :         /* ControlFile->checkPointCopy always tracks the latest ckpt XID */
    8538        1376 :         LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    8539        1376 :         ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
    8540        1376 :         LWLockRelease(ControlFileLock);
    8541             : 
    8542             :         /* TLI should not change in an on-line checkpoint */
    8543        1376 :         (void) GetCurrentReplayRecPtr(&replayTLI);
    8544        1376 :         if (checkPoint.ThisTimeLineID != replayTLI)
    8545           0 :             ereport(PANIC,
    8546             :                     (errmsg("unexpected timeline ID %u (should be %u) in online checkpoint record",
    8547             :                             checkPoint.ThisTimeLineID, replayTLI)));
    8548             : 
    8549        1376 :         RecoveryRestartPoint(&checkPoint, record);
    8550             : 
    8551             :         /*
    8552             :          * After replaying a checkpoint record, free all smgr objects.
    8553             :          * Otherwise we would never do so for dropped relations, as the
    8554             :          * startup does not process shared invalidation messages or call
    8555             :          * AtEOXact_SMgr().
    8556             :          */
    8557        1376 :         smgrdestroyall();
    8558             :     }
    8559       86402 :     else if (info == XLOG_OVERWRITE_CONTRECORD)
    8560             :     {
    8561             :         /* nothing to do here, handled in xlogrecovery_redo() */
    8562             :     }
    8563       86400 :     else if (info == XLOG_END_OF_RECOVERY)
    8564             :     {
    8565             :         xl_end_of_recovery xlrec;
    8566             :         TimeLineID  replayTLI;
    8567             : 
    8568          22 :         memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_end_of_recovery));
    8569             : 
    8570             :         /*
    8571             :          * For Hot Standby, we could treat this like a Shutdown Checkpoint,
    8572             :          * but this case is rarer and harder to test, so the benefit doesn't
    8573             :          * outweigh the potential extra cost of maintenance.
    8574             :          */
    8575             : 
    8576             :         /*
    8577             :          * We should've already switched to the new TLI before replaying this
    8578             :          * record.
    8579             :          */
    8580          22 :         (void) GetCurrentReplayRecPtr(&replayTLI);
    8581          22 :         if (xlrec.ThisTimeLineID != replayTLI)
    8582           0 :             ereport(PANIC,
    8583             :                     (errmsg("unexpected timeline ID %u (should be %u) in end-of-recovery record",
    8584             :                             xlrec.ThisTimeLineID, replayTLI)));
    8585             :     }
    8586       86378 :     else if (info == XLOG_NOOP)
    8587             :     {
    8588             :         /* nothing to do here */
    8589             :     }
    8590       86378 :     else if (info == XLOG_SWITCH)
    8591             :     {
    8592             :         /* nothing to do here */
    8593             :     }
    8594       85474 :     else if (info == XLOG_RESTORE_POINT)
    8595             :     {
    8596             :         /* nothing to do here, handled in xlogrecovery.c */
    8597             :     }
    8598       85464 :     else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
    8599             :     {
    8600             :         /*
    8601             :          * XLOG_FPI records contain nothing else but one or more block
    8602             :          * references. Every block reference must include a full-page image
    8603             :          * even if full_page_writes was disabled when the record was generated
    8604             :          * - otherwise there would be no point in this record.
    8605             :          *
    8606             :          * XLOG_FPI_FOR_HINT records are generated when a page needs to be
    8607             :          * WAL-logged because of a hint bit update. They are only generated
    8608             :          * when checksums and/or wal_log_hints are enabled. They may include
    8609             :          * no full-page images if full_page_writes was disabled when they were
    8610             :          * generated. In this case there is nothing to do here.
    8611             :          *
    8612             :          * No recovery conflicts are generated by these generic records - if a
    8613             :          * resource manager needs to generate conflicts, it has to define a
    8614             :          * separate WAL record type and redo routine.
    8615             :          */
    8616      177104 :         for (uint8 block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
    8617             :         {
    8618             :             Buffer      buffer;
    8619             : 
    8620       93316 :             if (!XLogRecHasBlockImage(record, block_id))
    8621             :             {
    8622         132 :                 if (info == XLOG_FPI)
    8623           0 :                     elog(ERROR, "XLOG_FPI record did not contain a full-page image");
    8624         132 :                 continue;
    8625             :             }
    8626             : 
    8627       93184 :             if (XLogReadBufferForRedo(record, block_id, &buffer) != BLK_RESTORED)
    8628           0 :                 elog(ERROR, "unexpected XLogReadBufferForRedo result when restoring backup block");
    8629       93184 :             UnlockReleaseBuffer(buffer);
    8630             :         }
    8631             :     }
    8632        1676 :     else if (info == XLOG_BACKUP_END)
    8633             :     {
    8634             :         /* nothing to do here, handled in xlogrecovery_redo() */
    8635             :     }
    8636        1490 :     else if (info == XLOG_PARAMETER_CHANGE)
    8637             :     {
    8638             :         xl_parameter_change xlrec;
    8639             : 
    8640             :         /* Update our copy of the parameters in pg_control */
    8641          76 :         memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_parameter_change));
    8642             : 
    8643          76 :         LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    8644          76 :         ControlFile->MaxConnections = xlrec.MaxConnections;
    8645          76 :         ControlFile->max_worker_processes = xlrec.max_worker_processes;
    8646          76 :         ControlFile->max_wal_senders = xlrec.max_wal_senders;
    8647          76 :         ControlFile->max_prepared_xacts = xlrec.max_prepared_xacts;
    8648          76 :         ControlFile->max_locks_per_xact = xlrec.max_locks_per_xact;
    8649          76 :         ControlFile->wal_level = xlrec.wal_level;
    8650          76 :         ControlFile->wal_log_hints = xlrec.wal_log_hints;
    8651             : 
    8652             :         /*
    8653             :          * Update minRecoveryPoint to ensure that if recovery is aborted, we
    8654             :          * recover back up to this point before allowing hot standby again.
    8655             :          * This is important if the max_* settings are decreased, to ensure
    8656             :          * you don't run queries against the WAL preceding the change. The
    8657             :          * local copies cannot be updated as long as crash recovery is
    8658             :          * happening and we expect all the WAL to be replayed.
    8659             :          */
    8660          76 :         if (InArchiveRecovery)
    8661             :         {
    8662          46 :             LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
    8663          46 :             LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
    8664             :         }
    8665          76 :         if (XLogRecPtrIsValid(LocalMinRecoveryPoint) && LocalMinRecoveryPoint < lsn)
    8666             :         {
    8667             :             TimeLineID  replayTLI;
    8668             : 
    8669          24 :             (void) GetCurrentReplayRecPtr(&replayTLI);
    8670          24 :             ControlFile->minRecoveryPoint = lsn;
    8671          24 :             ControlFile->minRecoveryPointTLI = replayTLI;
    8672             :         }
    8673             : 
    8674          76 :         CommitTsParameterChange(xlrec.track_commit_timestamp,
    8675          76 :                                 ControlFile->track_commit_timestamp);
    8676          76 :         ControlFile->track_commit_timestamp = xlrec.track_commit_timestamp;
    8677             : 
    8678          76 :         UpdateControlFile();
    8679          76 :         LWLockRelease(ControlFileLock);
    8680             : 
    8681             :         /* Check to see if any parameter change gives a problem on recovery */
    8682          76 :         CheckRequiredParameterValues();
    8683             :     }
    8684        1414 :     else if (info == XLOG_FPW_CHANGE)
    8685             :     {
    8686             :         bool        fpw;
    8687             : 
    8688           0 :         memcpy(&fpw, XLogRecGetData(record), sizeof(bool));
    8689             : 
    8690             :         /*
    8691             :          * Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
    8692             :          * do_pg_backup_start() and do_pg_backup_stop() can check whether
    8693             :          * full_page_writes has been disabled during online backup.
    8694             :          */
    8695           0 :         if (!fpw)
    8696             :         {
    8697           0 :             SpinLockAcquire(&XLogCtl->info_lck);
    8698           0 :             if (XLogCtl->lastFpwDisableRecPtr < record->ReadRecPtr)
    8699           0 :                 XLogCtl->lastFpwDisableRecPtr = record->ReadRecPtr;
    8700           0 :             SpinLockRelease(&XLogCtl->info_lck);
    8701             :         }
    8702             : 
    8703             :         /* Keep track of full_page_writes */
    8704           0 :         lastFullPageWrites = fpw;
    8705             :     }
    8706        1414 :     else if (info == XLOG_CHECKPOINT_REDO)
    8707             :     {
    8708             :         /* nothing to do here, just for informational purposes */
    8709             :     }
    8710          36 :     else if (info == XLOG_LOGICAL_DECODING_STATUS_CHANGE)
    8711             :     {
    8712             :         bool        status;
    8713             : 
    8714          36 :         memcpy(&status, XLogRecGetData(record), sizeof(bool));
    8715             : 
    8716             :         /*
    8717             :          * We need to toggle the logical decoding status and update the
    8718             :          * XLogLogicalInfo cache of processes synchronously because
    8719             :          * XLogLogicalInfoActive() is used even during read-only queries
    8720             :          * (e.g., via RelationIsAccessibleInLogicalDecoding()). In the
    8721             :          * 'disable' case, it is safe to invalidate existing slots after
    8722             :          * disabling logical decoding because logical decoding cannot process
    8723             :          * subsequent WAL records, which may not contain logical information.
    8724             :          */
    8725          36 :         if (status)
    8726          18 :             EnableLogicalDecoding();
    8727             :         else
    8728          18 :             DisableLogicalDecoding();
    8729             : 
    8730          36 :         elog(DEBUG1, "update logical decoding status to %d during recovery",
    8731             :              status);
    8732             : 
    8733          36 :         if (InRecovery && InHotStandby)
    8734             :         {
    8735          32 :             if (!status)
    8736             :             {
    8737             :                 /*
    8738             :                  * Invalidate logical slots if we are in hot standby and the
    8739             :                  * primary disabled logical decoding.
    8740             :                  */
    8741          18 :                 InvalidateObsoleteReplicationSlots(RS_INVAL_WAL_LEVEL,
    8742             :                                                    0, InvalidOid,
    8743             :                                                    InvalidTransactionId);
    8744             :             }
    8745          14 :             else if (sync_replication_slots)
    8746             :             {
    8747             :                 /*
    8748             :                  * Signal the postmaster to launch the slotsync worker.
    8749             :                  *
    8750             :                  * XXX: For simplicity, we keep the slotsync worker running
    8751             :                  * even after logical decoding is disabled. A future
    8752             :                  * improvement can consider starting and stopping the worker
    8753             :                  * based on logical decoding status change.
    8754             :                  */
    8755           0 :                 kill(PostmasterPid, SIGUSR1);
    8756             :             }
    8757             :         }
    8758             :     }
    8759       88044 : }
    8760             : 
    8761             : /*
    8762             :  * Return the extra open flags used for opening a file, depending on the
    8763             :  * value of the GUCs wal_sync_method, fsync and debug_io_direct.
    8764             :  */
    8765             : static int
    8766       32462 : get_sync_bit(int method)
    8767             : {
    8768       32462 :     int         o_direct_flag = 0;
    8769             : 
    8770             :     /*
    8771             :      * Use O_DIRECT if requested, except in walreceiver process.  The WAL
    8772             :      * written by walreceiver is normally read by the startup process soon
    8773             :      * after it's written.  Also, walreceiver performs unaligned writes, which
    8774             :      * don't work with O_DIRECT, so it is required for correctness too.
    8775             :      */
    8776       32462 :     if ((io_direct_flags & IO_DIRECT_WAL) && !AmWalReceiverProcess())
    8777          18 :         o_direct_flag = PG_O_DIRECT;
    8778             : 
    8779             :     /* If fsync is disabled, never open in sync mode */
    8780       32462 :     if (!enableFsync)
    8781       32462 :         return o_direct_flag;
    8782             : 
    8783           0 :     switch (method)
    8784             :     {
    8785             :             /*
    8786             :              * enum values for all sync options are defined even if they are
    8787             :              * not supported on the current platform.  But if not, they are
    8788             :              * not included in the enum option array, and therefore will never
    8789             :              * be seen here.
    8790             :              */
    8791           0 :         case WAL_SYNC_METHOD_FSYNC:
    8792             :         case WAL_SYNC_METHOD_FSYNC_WRITETHROUGH:
    8793             :         case WAL_SYNC_METHOD_FDATASYNC:
    8794           0 :             return o_direct_flag;
    8795             : #ifdef O_SYNC
    8796           0 :         case WAL_SYNC_METHOD_OPEN:
    8797           0 :             return O_SYNC | o_direct_flag;
    8798             : #endif
    8799             : #ifdef O_DSYNC
    8800           0 :         case WAL_SYNC_METHOD_OPEN_DSYNC:
    8801           0 :             return O_DSYNC | o_direct_flag;
    8802             : #endif
    8803           0 :         default:
    8804             :             /* can't happen (unless we are out of sync with option array) */
    8805           0 :             elog(ERROR, "unrecognized \"wal_sync_method\": %d", method);
    8806             :             return 0;           /* silence warning */
    8807             :     }
    8808             : }
    8809             : 
    8810             : /*
    8811             :  * GUC support
    8812             :  */
    8813             : void
    8814        2346 : assign_wal_sync_method(int new_wal_sync_method, void *extra)
    8815             : {
    8816        2346 :     if (wal_sync_method != new_wal_sync_method)
    8817             :     {
    8818             :         /*
    8819             :          * To ensure that no blocks escape unsynced, force an fsync on the
    8820             :          * currently open log segment (if any).  Also, if the open flag is
    8821             :          * changing, close the log file so it will be reopened (with new flag
    8822             :          * bit) at next use.
    8823             :          */
    8824           0 :         if (openLogFile >= 0)
    8825             :         {
    8826           0 :             pgstat_report_wait_start(WAIT_EVENT_WAL_SYNC_METHOD_ASSIGN);
    8827           0 :             if (pg_fsync(openLogFile) != 0)
    8828             :             {
    8829             :                 char        xlogfname[MAXFNAMELEN];
    8830             :                 int         save_errno;
    8831             : 
    8832           0 :                 save_errno = errno;
    8833           0 :                 XLogFileName(xlogfname, openLogTLI, openLogSegNo,
    8834             :                              wal_segment_size);
    8835           0 :                 errno = save_errno;
    8836           0 :                 ereport(PANIC,
    8837             :                         (errcode_for_file_access(),
    8838             :                          errmsg("could not fsync file \"%s\": %m", xlogfname)));
    8839             :             }
    8840             : 
    8841           0 :             pgstat_report_wait_end();
    8842           0 :             if (get_sync_bit(wal_sync_method) != get_sync_bit(new_wal_sync_method))
    8843           0 :                 XLogFileClose();
    8844             :         }
    8845             :     }
    8846        2346 : }
    8847             : 
    8848             : 
    8849             : /*
    8850             :  * Issue appropriate kind of fsync (if any) for an XLOG output file.
    8851             :  *
    8852             :  * 'fd' is a file descriptor for the XLOG file to be fsync'd.
    8853             :  * 'segno' is for error reporting purposes.
    8854             :  */
    8855             : void
    8856      324854 : issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
    8857             : {
    8858      324854 :     char       *msg = NULL;
    8859             :     instr_time  start;
    8860             : 
    8861             :     Assert(tli != 0);
    8862             : 
    8863             :     /*
    8864             :      * Quick exit if fsync is disabled or write() has already synced the WAL
    8865             :      * file.
    8866             :      */
    8867      324854 :     if (!enableFsync ||
    8868           0 :         wal_sync_method == WAL_SYNC_METHOD_OPEN ||
    8869           0 :         wal_sync_method == WAL_SYNC_METHOD_OPEN_DSYNC)
    8870      324854 :         return;
    8871             : 
    8872             :     /*
    8873             :      * Measure I/O timing to sync the WAL file for pg_stat_io.
    8874             :      */
    8875           0 :     start = pgstat_prepare_io_time(track_wal_io_timing);
    8876             : 
    8877           0 :     pgstat_report_wait_start(WAIT_EVENT_WAL_SYNC);
    8878           0 :     switch (wal_sync_method)
    8879             :     {
    8880           0 :         case WAL_SYNC_METHOD_FSYNC:
    8881           0 :             if (pg_fsync_no_writethrough(fd) != 0)
    8882           0 :                 msg = _("could not fsync file \"%s\": %m");
    8883           0 :             break;
    8884             : #ifdef HAVE_FSYNC_WRITETHROUGH
    8885             :         case WAL_SYNC_METHOD_FSYNC_WRITETHROUGH:
    8886             :             if (pg_fsync_writethrough(fd) != 0)
    8887             :                 msg = _("could not fsync write-through file \"%s\": %m");
    8888             :             break;
    8889             : #endif
    8890           0 :         case WAL_SYNC_METHOD_FDATASYNC:
    8891           0 :             if (pg_fdatasync(fd) != 0)
    8892           0 :                 msg = _("could not fdatasync file \"%s\": %m");
    8893           0 :             break;
    8894           0 :         case WAL_SYNC_METHOD_OPEN:
    8895             :         case WAL_SYNC_METHOD_OPEN_DSYNC:
    8896             :             /* not reachable */
    8897             :             Assert(false);
    8898           0 :             break;
    8899           0 :         default:
    8900           0 :             ereport(PANIC,
    8901             :                     errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    8902             :                     errmsg_internal("unrecognized \"wal_sync_method\": %d", wal_sync_method));
    8903             :             break;
    8904             :     }
    8905             : 
    8906             :     /* PANIC if failed to fsync */
    8907           0 :     if (msg)
    8908             :     {
    8909             :         char        xlogfname[MAXFNAMELEN];
    8910           0 :         int         save_errno = errno;
    8911             : 
    8912           0 :         XLogFileName(xlogfname, tli, segno, wal_segment_size);
    8913           0 :         errno = save_errno;
    8914           0 :         ereport(PANIC,
    8915             :                 (errcode_for_file_access(),
    8916             :                  errmsg(msg, xlogfname)));
    8917             :     }
    8918             : 
    8919           0 :     pgstat_report_wait_end();
    8920             : 
    8921           0 :     pgstat_count_io_op_time(IOOBJECT_WAL, IOCONTEXT_NORMAL, IOOP_FSYNC,
    8922             :                             start, 1, 0);
    8923             : }
    8924             : 
    8925             : /*
    8926             :  * do_pg_backup_start is the workhorse of the user-visible pg_backup_start()
    8927             :  * function. It creates the necessary starting checkpoint and constructs the
    8928             :  * backup state and tablespace map.
    8929             :  *
    8930             :  * Input parameters are "state" (the backup state), "fast" (if true, we do
    8931             :  * the checkpoint in fast mode), and "tablespaces" (if non-NULL, indicates a
    8932             :  * list of tablespaceinfo structs describing the cluster's tablespaces.).
    8933             :  *
    8934             :  * The tablespace map contents are appended to passed-in parameter
    8935             :  * tablespace_map and the caller is responsible for including it in the backup
    8936             :  * archive as 'tablespace_map'. The tablespace_map file is required mainly for
    8937             :  * tar format in windows as native windows utilities are not able to create
    8938             :  * symlinks while extracting files from tar. However for consistency and
    8939             :  * platform-independence, we do it the same way everywhere.
    8940             :  *
    8941             :  * It fills in "state" with the information required for the backup, such
    8942             :  * as the minimum WAL location that must be present to restore from this
    8943             :  * backup (starttli) and the corresponding timeline ID (starttli).
    8944             :  *
    8945             :  * Every successfully started backup must be stopped by calling
    8946             :  * do_pg_backup_stop() or do_pg_abort_backup(). There can be many
    8947             :  * backups active at the same time.
    8948             :  *
    8949             :  * It is the responsibility of the caller of this function to verify the
    8950             :  * permissions of the calling user!
    8951             :  */
    8952             : void
    8953         332 : do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces,
    8954             :                    BackupState *state, StringInfo tblspcmapfile)
    8955             : {
    8956             :     bool        backup_started_in_recovery;
    8957             : 
    8958             :     Assert(state != NULL);
    8959         332 :     backup_started_in_recovery = RecoveryInProgress();
    8960             : 
    8961             :     /*
    8962             :      * During recovery, we don't need to check WAL level. Because, if WAL
    8963             :      * level is not sufficient, it's impossible to get here during recovery.
    8964             :      */
    8965         332 :     if (!backup_started_in_recovery && !XLogIsNeeded())
    8966           0 :         ereport(ERROR,
    8967             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    8968             :                  errmsg("WAL level not sufficient for making an online backup"),
    8969             :                  errhint("\"wal_level\" must be set to \"replica\" or \"logical\" at server start.")));
    8970             : 
    8971         332 :     if (strlen(backupidstr) > MAXPGPATH)
    8972           2 :         ereport(ERROR,
    8973             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    8974             :                  errmsg("backup label too long (max %d bytes)",
    8975             :                         MAXPGPATH)));
    8976             : 
    8977         330 :     strlcpy(state->name, backupidstr, sizeof(state->name));
    8978             : 
    8979             :     /*
    8980             :      * Mark backup active in shared memory.  We must do full-page WAL writes
    8981             :      * during an on-line backup even if not doing so at other times, because
    8982             :      * it's quite possible for the backup dump to obtain a "torn" (partially
    8983             :      * written) copy of a database page if it reads the page concurrently with
    8984             :      * our write to the same page.  This can be fixed as long as the first
    8985             :      * write to the page in the WAL sequence is a full-page write. Hence, we
    8986             :      * increment runningBackups then force a CHECKPOINT, to ensure there are
    8987             :      * no dirty pages in shared memory that might get dumped while the backup
    8988             :      * is in progress without having a corresponding WAL record.  (Once the
    8989             :      * backup is complete, we need not force full-page writes anymore, since
    8990             :      * we expect that any pages not modified during the backup interval must
    8991             :      * have been correctly captured by the backup.)
    8992             :      *
    8993             :      * Note that forcing full-page writes has no effect during an online
    8994             :      * backup from the standby.
    8995             :      *
    8996             :      * We must hold all the insertion locks to change the value of
    8997             :      * runningBackups, to ensure adequate interlocking against
    8998             :      * XLogInsertRecord().
    8999             :      */
    9000         330 :     WALInsertLockAcquireExclusive();
    9001         330 :     XLogCtl->Insert.runningBackups++;
    9002         330 :     WALInsertLockRelease();
    9003             : 
    9004             :     /*
    9005             :      * Ensure we decrement runningBackups if we fail below. NB -- for this to
    9006             :      * work correctly, it is critical that sessionBackupState is only updated
    9007             :      * after this block is over.
    9008             :      */
    9009         330 :     PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(true));
    9010             :     {
    9011         330 :         bool        gotUniqueStartpoint = false;
    9012             :         DIR        *tblspcdir;
    9013             :         struct dirent *de;
    9014             :         tablespaceinfo *ti;
    9015             :         int         datadirpathlen;
    9016             : 
    9017             :         /*
    9018             :          * Force an XLOG file switch before the checkpoint, to ensure that the
    9019             :          * WAL segment the checkpoint is written to doesn't contain pages with
    9020             :          * old timeline IDs.  That would otherwise happen if you called
    9021             :          * pg_backup_start() right after restoring from a PITR archive: the
    9022             :          * first WAL segment containing the startup checkpoint has pages in
    9023             :          * the beginning with the old timeline ID.  That can cause trouble at
    9024             :          * recovery: we won't have a history file covering the old timeline if
    9025             :          * pg_wal directory was not included in the base backup and the WAL
    9026             :          * archive was cleared too before starting the backup.
    9027             :          *
    9028             :          * This also ensures that we have emitted a WAL page header that has
    9029             :          * XLP_BKP_REMOVABLE off before we emit the checkpoint record.
    9030             :          * Therefore, if a WAL archiver (such as pglesslog) is trying to
    9031             :          * compress out removable backup blocks, it won't remove any that
    9032             :          * occur after this point.
    9033             :          *
    9034             :          * During recovery, we skip forcing XLOG file switch, which means that
    9035             :          * the backup taken during recovery is not available for the special
    9036             :          * recovery case described above.
    9037             :          */
    9038         330 :         if (!backup_started_in_recovery)
    9039         314 :             RequestXLogSwitch(false);
    9040             : 
    9041             :         do
    9042             :         {
    9043             :             bool        checkpointfpw;
    9044             : 
    9045             :             /*
    9046             :              * Force a CHECKPOINT.  Aside from being necessary to prevent torn
    9047             :              * page problems, this guarantees that two successive backup runs
    9048             :              * will have different checkpoint positions and hence different
    9049             :              * history file names, even if nothing happened in between.
    9050             :              *
    9051             :              * During recovery, establish a restartpoint if possible. We use
    9052             :              * the last restartpoint as the backup starting checkpoint. This
    9053             :              * means that two successive backup runs can have same checkpoint
    9054             :              * positions.
    9055             :              *
    9056             :              * Since the fact that we are executing do_pg_backup_start()
    9057             :              * during recovery means that checkpointer is running, we can use
    9058             :              * RequestCheckpoint() to establish a restartpoint.
    9059             :              *
    9060             :              * We use CHECKPOINT_FAST only if requested by user (via passing
    9061             :              * fast = true).  Otherwise this can take awhile.
    9062             :              */
    9063         330 :             RequestCheckpoint(CHECKPOINT_FORCE | CHECKPOINT_WAIT |
    9064             :                               (fast ? CHECKPOINT_FAST : 0));
    9065             : 
    9066             :             /*
    9067             :              * Now we need to fetch the checkpoint record location, and also
    9068             :              * its REDO pointer.  The oldest point in WAL that would be needed
    9069             :              * to restore starting from the checkpoint is precisely the REDO
    9070             :              * pointer.
    9071             :              */
    9072         330 :             LWLockAcquire(ControlFileLock, LW_SHARED);
    9073         330 :             state->checkpointloc = ControlFile->checkPoint;
    9074         330 :             state->startpoint = ControlFile->checkPointCopy.redo;
    9075         330 :             state->starttli = ControlFile->checkPointCopy.ThisTimeLineID;
    9076         330 :             checkpointfpw = ControlFile->checkPointCopy.fullPageWrites;
    9077         330 :             LWLockRelease(ControlFileLock);
    9078             : 
    9079         330 :             if (backup_started_in_recovery)
    9080             :             {
    9081             :                 XLogRecPtr  recptr;
    9082             : 
    9083             :                 /*
    9084             :                  * Check to see if all WAL replayed during online backup
    9085             :                  * (i.e., since last restartpoint used as backup starting
    9086             :                  * checkpoint) contain full-page writes.
    9087             :                  */
    9088          16 :                 SpinLockAcquire(&XLogCtl->info_lck);
    9089          16 :                 recptr = XLogCtl->lastFpwDisableRecPtr;
    9090          16 :                 SpinLockRelease(&XLogCtl->info_lck);
    9091             : 
    9092          16 :                 if (!checkpointfpw || state->startpoint <= recptr)
    9093           0 :                     ereport(ERROR,
    9094             :                             (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    9095             :                              errmsg("WAL generated with \"full_page_writes=off\" was replayed "
    9096             :                                     "since last restartpoint"),
    9097             :                              errhint("This means that the backup being taken on the standby "
    9098             :                                      "is corrupt and should not be used. "
    9099             :                                      "Enable \"full_page_writes\" and run CHECKPOINT on the primary, "
    9100             :                                      "and then try an online backup again.")));
    9101             : 
    9102             :                 /*
    9103             :                  * During recovery, since we don't use the end-of-backup WAL
    9104             :                  * record and don't write the backup history file, the
    9105             :                  * starting WAL location doesn't need to be unique. This means
    9106             :                  * that two base backups started at the same time might use
    9107             :                  * the same checkpoint as starting locations.
    9108             :                  */
    9109          16 :                 gotUniqueStartpoint = true;
    9110             :             }
    9111             : 
    9112             :             /*
    9113             :              * If two base backups are started at the same time (in WAL sender
    9114             :              * processes), we need to make sure that they use different
    9115             :              * checkpoints as starting locations, because we use the starting
    9116             :              * WAL location as a unique identifier for the base backup in the
    9117             :              * end-of-backup WAL record and when we write the backup history
    9118             :              * file. Perhaps it would be better generate a separate unique ID
    9119             :              * for each backup instead of forcing another checkpoint, but
    9120             :              * taking a checkpoint right after another is not that expensive
    9121             :              * either because only few buffers have been dirtied yet.
    9122             :              */
    9123         330 :             WALInsertLockAcquireExclusive();
    9124         330 :             if (XLogCtl->Insert.lastBackupStart < state->startpoint)
    9125             :             {
    9126         330 :                 XLogCtl->Insert.lastBackupStart = state->startpoint;
    9127         330 :                 gotUniqueStartpoint = true;
    9128             :             }
    9129         330 :             WALInsertLockRelease();
    9130         330 :         } while (!gotUniqueStartpoint);
    9131             : 
    9132             :         /*
    9133             :          * Construct tablespace_map file.
    9134             :          */
    9135         330 :         datadirpathlen = strlen(DataDir);
    9136             : 
    9137             :         /* Collect information about all tablespaces */
    9138         330 :         tblspcdir = AllocateDir(PG_TBLSPC_DIR);
    9139        1064 :         while ((de = ReadDir(tblspcdir, PG_TBLSPC_DIR)) != NULL)
    9140             :         {
    9141             :             char        fullpath[MAXPGPATH + sizeof(PG_TBLSPC_DIR)];
    9142             :             char        linkpath[MAXPGPATH];
    9143         734 :             char       *relpath = NULL;
    9144             :             char       *s;
    9145             :             PGFileType  de_type;
    9146             :             char       *badp;
    9147             :             Oid         tsoid;
    9148             : 
    9149             :             /*
    9150             :              * Try to parse the directory name as an unsigned integer.
    9151             :              *
    9152             :              * Tablespace directories should be positive integers that can be
    9153             :              * represented in 32 bits, with no leading zeroes or trailing
    9154             :              * garbage. If we come across a name that doesn't meet those
    9155             :              * criteria, skip it.
    9156             :              */
    9157         734 :             if (de->d_name[0] < '1' || de->d_name[1] > '9')
    9158         660 :                 continue;
    9159          74 :             errno = 0;
    9160          74 :             tsoid = strtoul(de->d_name, &badp, 10);
    9161          74 :             if (*badp != '\0' || errno == EINVAL || errno == ERANGE)
    9162           0 :                 continue;
    9163             : 
    9164          74 :             snprintf(fullpath, sizeof(fullpath), "%s/%s", PG_TBLSPC_DIR, de->d_name);
    9165             : 
    9166          74 :             de_type = get_dirent_type(fullpath, de, false, ERROR);
    9167             : 
    9168          74 :             if (de_type == PGFILETYPE_LNK)
    9169             :             {
    9170             :                 StringInfoData escapedpath;
    9171             :                 int         rllen;
    9172             : 
    9173          46 :                 rllen = readlink(fullpath, linkpath, sizeof(linkpath));
    9174          46 :                 if (rllen < 0)
    9175             :                 {
    9176           0 :                     ereport(WARNING,
    9177             :                             (errmsg("could not read symbolic link \"%s\": %m",
    9178             :                                     fullpath)));
    9179           0 :                     continue;
    9180             :                 }
    9181          46 :                 else if (rllen >= sizeof(linkpath))
    9182             :                 {
    9183           0 :                     ereport(WARNING,
    9184             :                             (errmsg("symbolic link \"%s\" target is too long",
    9185             :                                     fullpath)));
    9186           0 :                     continue;
    9187             :                 }
    9188          46 :                 linkpath[rllen] = '\0';
    9189             : 
    9190             :                 /*
    9191             :                  * Relpath holds the relative path of the tablespace directory
    9192             :                  * when it's located within PGDATA, or NULL if it's located
    9193             :                  * elsewhere.
    9194             :                  */
    9195          46 :                 if (rllen > datadirpathlen &&
    9196           2 :                     strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
    9197           0 :                     IS_DIR_SEP(linkpath[datadirpathlen]))
    9198           0 :                     relpath = pstrdup(linkpath + datadirpathlen + 1);
    9199             : 
    9200             :                 /*
    9201             :                  * Add a backslash-escaped version of the link path to the
    9202             :                  * tablespace map file.
    9203             :                  */
    9204          46 :                 initStringInfo(&escapedpath);
    9205        1124 :                 for (s = linkpath; *s; s++)
    9206             :                 {
    9207        1078 :                     if (*s == '\n' || *s == '\r' || *s == '\\')
    9208           0 :                         appendStringInfoChar(&escapedpath, '\\');
    9209        1078 :                     appendStringInfoChar(&escapedpath, *s);
    9210             :                 }
    9211          46 :                 appendStringInfo(tblspcmapfile, "%s %s\n",
    9212          46 :                                  de->d_name, escapedpath.data);
    9213          46 :                 pfree(escapedpath.data);
    9214             :             }
    9215          28 :             else if (de_type == PGFILETYPE_DIR)
    9216             :             {
    9217             :                 /*
    9218             :                  * It's possible to use allow_in_place_tablespaces to create
    9219             :                  * directories directly under pg_tblspc, for testing purposes
    9220             :                  * only.
    9221             :                  *
    9222             :                  * In this case, we store a relative path rather than an
    9223             :                  * absolute path into the tablespaceinfo.
    9224             :                  */
    9225          28 :                 snprintf(linkpath, sizeof(linkpath), "%s/%s",
    9226          28 :                          PG_TBLSPC_DIR, de->d_name);
    9227          28 :                 relpath = pstrdup(linkpath);
    9228             :             }
    9229             :             else
    9230             :             {
    9231             :                 /* Skip any other file type that appears here. */
    9232           0 :                 continue;
    9233             :             }
    9234             : 
    9235          74 :             ti = palloc_object(tablespaceinfo);
    9236          74 :             ti->oid = tsoid;
    9237          74 :             ti->path = pstrdup(linkpath);
    9238          74 :             ti->rpath = relpath;
    9239          74 :             ti->size = -1;
    9240             : 
    9241          74 :             if (tablespaces)
    9242          74 :                 *tablespaces = lappend(*tablespaces, ti);
    9243             :         }
    9244         330 :         FreeDir(tblspcdir);
    9245             : 
    9246         330 :         state->starttime = (pg_time_t) time(NULL);
    9247             :     }
    9248         330 :     PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(true));
    9249             : 
    9250         330 :     state->started_in_recovery = backup_started_in_recovery;
    9251             : 
    9252             :     /*
    9253             :      * Mark that the start phase has correctly finished for the backup.
    9254             :      */
    9255         330 :     sessionBackupState = SESSION_BACKUP_RUNNING;
    9256         330 : }
    9257             : 
    9258             : /*
    9259             :  * Utility routine to fetch the session-level status of a backup running.
    9260             :  */
    9261             : SessionBackupState
    9262         372 : get_backup_status(void)
    9263             : {
    9264         372 :     return sessionBackupState;
    9265             : }
    9266             : 
    9267             : /*
    9268             :  * do_pg_backup_stop
    9269             :  *
    9270             :  * Utility function called at the end of an online backup.  It creates history
    9271             :  * file (if required), resets sessionBackupState and so on.  It can optionally
    9272             :  * wait for WAL segments to be archived.
    9273             :  *
    9274             :  * "state" is filled with the information necessary to restore from this
    9275             :  * backup with its stop LSN (stoppoint), its timeline ID (stoptli), etc.
    9276             :  *
    9277             :  * It is the responsibility of the caller of this function to verify the
    9278             :  * permissions of the calling user!
    9279             :  */
    9280             : void
    9281         318 : do_pg_backup_stop(BackupState *state, bool waitforarchive)
    9282             : {
    9283         318 :     bool        backup_stopped_in_recovery = false;
    9284             :     char        histfilepath[MAXPGPATH];
    9285             :     char        lastxlogfilename[MAXFNAMELEN];
    9286             :     char        histfilename[MAXFNAMELEN];
    9287             :     XLogSegNo   _logSegNo;
    9288             :     FILE       *fp;
    9289             :     int         seconds_before_warning;
    9290         318 :     int         waits = 0;
    9291         318 :     bool        reported_waiting = false;
    9292             : 
    9293             :     Assert(state != NULL);
    9294             : 
    9295         318 :     backup_stopped_in_recovery = RecoveryInProgress();
    9296             : 
    9297             :     /*
    9298             :      * During recovery, we don't need to check WAL level. Because, if WAL
    9299             :      * level is not sufficient, it's impossible to get here during recovery.
    9300             :      */
    9301         318 :     if (!backup_stopped_in_recovery && !XLogIsNeeded())
    9302           0 :         ereport(ERROR,
    9303             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    9304             :                  errmsg("WAL level not sufficient for making an online backup"),
    9305             :                  errhint("\"wal_level\" must be set to \"replica\" or \"logical\" at server start.")));
    9306             : 
    9307             :     /*
    9308             :      * OK to update backup counter and session-level lock.
    9309             :      *
    9310             :      * Note that CHECK_FOR_INTERRUPTS() must not occur while updating them,
    9311             :      * otherwise they can be updated inconsistently, which might cause
    9312             :      * do_pg_abort_backup() to fail.
    9313             :      */
    9314         318 :     WALInsertLockAcquireExclusive();
    9315             : 
    9316             :     /*
    9317             :      * It is expected that each do_pg_backup_start() call is matched by
    9318             :      * exactly one do_pg_backup_stop() call.
    9319             :      */
    9320             :     Assert(XLogCtl->Insert.runningBackups > 0);
    9321         318 :     XLogCtl->Insert.runningBackups--;
    9322             : 
    9323             :     /*
    9324             :      * Clean up session-level lock.
    9325             :      *
    9326             :      * You might think that WALInsertLockRelease() can be called before
    9327             :      * cleaning up session-level lock because session-level lock doesn't need
    9328             :      * to be protected with WAL insertion lock. But since
    9329             :      * CHECK_FOR_INTERRUPTS() can occur in it, session-level lock must be
    9330             :      * cleaned up before it.
    9331             :      */
    9332         318 :     sessionBackupState = SESSION_BACKUP_NONE;
    9333             : 
    9334         318 :     WALInsertLockRelease();
    9335             : 
    9336             :     /*
    9337             :      * If we are taking an online backup from the standby, we confirm that the
    9338             :      * standby has not been promoted during the backup.
    9339             :      */
    9340         318 :     if (state->started_in_recovery && !backup_stopped_in_recovery)
    9341           0 :         ereport(ERROR,
    9342             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    9343             :                  errmsg("the standby was promoted during online backup"),
    9344             :                  errhint("This means that the backup being taken is corrupt "
    9345             :                          "and should not be used. "
    9346             :                          "Try taking another online backup.")));
    9347             : 
    9348             :     /*
    9349             :      * During recovery, we don't write an end-of-backup record. We assume that
    9350             :      * pg_control was backed up last and its minimum recovery point can be
    9351             :      * available as the backup end location. Since we don't have an
    9352             :      * end-of-backup record, we use the pg_control value to check whether
    9353             :      * we've reached the end of backup when starting recovery from this
    9354             :      * backup. We have no way of checking if pg_control wasn't backed up last
    9355             :      * however.
    9356             :      *
    9357             :      * We don't force a switch to new WAL file but it is still possible to
    9358             :      * wait for all the required files to be archived if waitforarchive is
    9359             :      * true. This is okay if we use the backup to start a standby and fetch
    9360             :      * the missing WAL using streaming replication. But in the case of an
    9361             :      * archive recovery, a user should set waitforarchive to true and wait for
    9362             :      * them to be archived to ensure that all the required files are
    9363             :      * available.
    9364             :      *
    9365             :      * We return the current minimum recovery point as the backup end
    9366             :      * location. Note that it can be greater than the exact backup end
    9367             :      * location if the minimum recovery point is updated after the backup of
    9368             :      * pg_control. This is harmless for current uses.
    9369             :      *
    9370             :      * XXX currently a backup history file is for informational and debug
    9371             :      * purposes only. It's not essential for an online backup. Furthermore,
    9372             :      * even if it's created, it will not be archived during recovery because
    9373             :      * an archiver is not invoked. So it doesn't seem worthwhile to write a
    9374             :      * backup history file during recovery.
    9375             :      */
    9376         318 :     if (backup_stopped_in_recovery)
    9377             :     {
    9378             :         XLogRecPtr  recptr;
    9379             : 
    9380             :         /*
    9381             :          * Check to see if all WAL replayed during online backup contain
    9382             :          * full-page writes.
    9383             :          */
    9384          16 :         SpinLockAcquire(&XLogCtl->info_lck);
    9385          16 :         recptr = XLogCtl->lastFpwDisableRecPtr;
    9386          16 :         SpinLockRelease(&XLogCtl->info_lck);
    9387             : 
    9388          16 :         if (state->startpoint <= recptr)
    9389           0 :             ereport(ERROR,
    9390             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    9391             :                      errmsg("WAL generated with \"full_page_writes=off\" was replayed "
    9392             :                             "during online backup"),
    9393             :                      errhint("This means that the backup being taken on the standby "
    9394             :                              "is corrupt and should not be used. "
    9395             :                              "Enable \"full_page_writes\" and run CHECKPOINT on the primary, "
    9396             :                              "and then try an online backup again.")));
    9397             : 
    9398             : 
    9399          16 :         LWLockAcquire(ControlFileLock, LW_SHARED);
    9400          16 :         state->stoppoint = ControlFile->minRecoveryPoint;
    9401          16 :         state->stoptli = ControlFile->minRecoveryPointTLI;
    9402          16 :         LWLockRelease(ControlFileLock);
    9403             :     }
    9404             :     else
    9405             :     {
    9406             :         char       *history_file;
    9407             : 
    9408             :         /*
    9409             :          * Write the backup-end xlog record
    9410             :          */
    9411         302 :         XLogBeginInsert();
    9412         302 :         XLogRegisterData(&state->startpoint,
    9413             :                          sizeof(state->startpoint));
    9414         302 :         state->stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END);
    9415             : 
    9416             :         /*
    9417             :          * Given that we're not in recovery, InsertTimeLineID is set and can't
    9418             :          * change, so we can read it without a lock.
    9419             :          */
    9420         302 :         state->stoptli = XLogCtl->InsertTimeLineID;
    9421             : 
    9422             :         /*
    9423             :          * Force a switch to a new xlog segment file, so that the backup is
    9424             :          * valid as soon as archiver moves out the current segment file.
    9425             :          */
    9426         302 :         RequestXLogSwitch(false);
    9427             : 
    9428         302 :         state->stoptime = (pg_time_t) time(NULL);
    9429             : 
    9430             :         /*
    9431             :          * Write the backup history file
    9432             :          */
    9433         302 :         XLByteToSeg(state->startpoint, _logSegNo, wal_segment_size);
    9434         302 :         BackupHistoryFilePath(histfilepath, state->stoptli, _logSegNo,
    9435             :                               state->startpoint, wal_segment_size);
    9436         302 :         fp = AllocateFile(histfilepath, "w");
    9437         302 :         if (!fp)
    9438           0 :             ereport(ERROR,
    9439             :                     (errcode_for_file_access(),
    9440             :                      errmsg("could not create file \"%s\": %m",
    9441             :                             histfilepath)));
    9442             : 
    9443             :         /* Build and save the contents of the backup history file */
    9444         302 :         history_file = build_backup_content(state, true);
    9445         302 :         fprintf(fp, "%s", history_file);
    9446         302 :         pfree(history_file);
    9447             : 
    9448         302 :         if (fflush(fp) || ferror(fp) || FreeFile(fp))
    9449           0 :             ereport(ERROR,
    9450             :                     (errcode_for_file_access(),
    9451             :                      errmsg("could not write file \"%s\": %m",
    9452             :                             histfilepath)));
    9453             : 
    9454             :         /*
    9455             :          * Clean out any no-longer-needed history files.  As a side effect,
    9456             :          * this will post a .ready file for the newly created history file,
    9457             :          * notifying the archiver that history file may be archived
    9458             :          * immediately.
    9459             :          */
    9460         302 :         CleanupBackupHistory();
    9461             :     }
    9462             : 
    9463             :     /*
    9464             :      * If archiving is enabled, wait for all the required WAL files to be
    9465             :      * archived before returning. If archiving isn't enabled, the required WAL
    9466             :      * needs to be transported via streaming replication (hopefully with
    9467             :      * wal_keep_size set high enough), or some more exotic mechanism like
    9468             :      * polling and copying files from pg_wal with script. We have no knowledge
    9469             :      * of those mechanisms, so it's up to the user to ensure that he gets all
    9470             :      * the required WAL.
    9471             :      *
    9472             :      * We wait until both the last WAL file filled during backup and the
    9473             :      * history file have been archived, and assume that the alphabetic sorting
    9474             :      * property of the WAL files ensures any earlier WAL files are safely
    9475             :      * archived as well.
    9476             :      *
    9477             :      * We wait forever, since archive_command is supposed to work and we
    9478             :      * assume the admin wanted his backup to work completely. If you don't
    9479             :      * wish to wait, then either waitforarchive should be passed in as false,
    9480             :      * or you can set statement_timeout.  Also, some notices are issued to
    9481             :      * clue in anyone who might be doing this interactively.
    9482             :      */
    9483             : 
    9484         318 :     if (waitforarchive &&
    9485          20 :         ((!backup_stopped_in_recovery && XLogArchivingActive()) ||
    9486           2 :          (backup_stopped_in_recovery && XLogArchivingAlways())))
    9487             :     {
    9488           8 :         XLByteToPrevSeg(state->stoppoint, _logSegNo, wal_segment_size);
    9489           8 :         XLogFileName(lastxlogfilename, state->stoptli, _logSegNo,
    9490             :                      wal_segment_size);
    9491             : 
    9492           8 :         XLByteToSeg(state->startpoint, _logSegNo, wal_segment_size);
    9493           8 :         BackupHistoryFileName(histfilename, state->stoptli, _logSegNo,
    9494             :                               state->startpoint, wal_segment_size);
    9495             : 
    9496           8 :         seconds_before_warning = 60;
    9497           8 :         waits = 0;
    9498             : 
    9499          26 :         while (XLogArchiveIsBusy(lastxlogfilename) ||
    9500           8 :                XLogArchiveIsBusy(histfilename))
    9501             :         {
    9502          10 :             CHECK_FOR_INTERRUPTS();
    9503             : 
    9504          10 :             if (!reported_waiting && waits > 5)
    9505             :             {
    9506           0 :                 ereport(NOTICE,
    9507             :                         (errmsg("base backup done, waiting for required WAL segments to be archived")));
    9508           0 :                 reported_waiting = true;
    9509             :             }
    9510             : 
    9511          10 :             (void) WaitLatch(MyLatch,
    9512             :                              WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
    9513             :                              1000L,
    9514             :                              WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE);
    9515          10 :             ResetLatch(MyLatch);
    9516             : 
    9517          10 :             if (++waits >= seconds_before_warning)
    9518             :             {
    9519           0 :                 seconds_before_warning *= 2;    /* This wraps in >10 years... */
    9520           0 :                 ereport(WARNING,
    9521             :                         (errmsg("still waiting for all required WAL segments to be archived (%d seconds elapsed)",
    9522             :                                 waits),
    9523             :                          errhint("Check that your \"archive_command\" is executing properly.  "
    9524             :                                  "You can safely cancel this backup, "
    9525             :                                  "but the database backup will not be usable without all the WAL segments.")));
    9526             :             }
    9527             :         }
    9528             : 
    9529           8 :         ereport(NOTICE,
    9530             :                 (errmsg("all required WAL segments have been archived")));
    9531             :     }
    9532         310 :     else if (waitforarchive)
    9533          12 :         ereport(NOTICE,
    9534             :                 (errmsg("WAL archiving is not enabled; you must ensure that all required WAL segments are copied through other means to complete the backup")));
    9535         318 : }
    9536             : 
    9537             : 
    9538             : /*
    9539             :  * do_pg_abort_backup: abort a running backup
    9540             :  *
    9541             :  * This does just the most basic steps of do_pg_backup_stop(), by taking the
    9542             :  * system out of backup mode, thus making it a lot more safe to call from
    9543             :  * an error handler.
    9544             :  *
    9545             :  * 'arg' indicates that it's being called during backup setup; so
    9546             :  * sessionBackupState has not been modified yet, but runningBackups has
    9547             :  * already been incremented.  When it's false, then it's invoked as a
    9548             :  * before_shmem_exit handler, and therefore we must not change state
    9549             :  * unless sessionBackupState indicates that a backup is actually running.
    9550             :  *
    9551             :  * NB: This gets used as a PG_ENSURE_ERROR_CLEANUP callback and
    9552             :  * before_shmem_exit handler, hence the odd-looking signature.
    9553             :  */
    9554             : void
    9555          16 : do_pg_abort_backup(int code, Datum arg)
    9556             : {
    9557          16 :     bool        during_backup_start = DatumGetBool(arg);
    9558             : 
    9559             :     /* If called during backup start, there shouldn't be one already running */
    9560             :     Assert(!during_backup_start || sessionBackupState == SESSION_BACKUP_NONE);
    9561             : 
    9562          16 :     if (during_backup_start || sessionBackupState != SESSION_BACKUP_NONE)
    9563             :     {
    9564          12 :         WALInsertLockAcquireExclusive();
    9565             :         Assert(XLogCtl->Insert.runningBackups > 0);
    9566          12 :         XLogCtl->Insert.runningBackups--;
    9567             : 
    9568          12 :         sessionBackupState = SESSION_BACKUP_NONE;
    9569          12 :         WALInsertLockRelease();
    9570             : 
    9571          12 :         if (!during_backup_start)
    9572          12 :             ereport(WARNING,
    9573             :                     errmsg("aborting backup due to backend exiting before pg_backup_stop was called"));
    9574             :     }
    9575          16 : }
    9576             : 
    9577             : /*
    9578             :  * Register a handler that will warn about unterminated backups at end of
    9579             :  * session, unless this has already been done.
    9580             :  */
    9581             : void
    9582           8 : register_persistent_abort_backup_handler(void)
    9583             : {
    9584             :     static bool already_done = false;
    9585             : 
    9586           8 :     if (already_done)
    9587           2 :         return;
    9588           6 :     before_shmem_exit(do_pg_abort_backup, BoolGetDatum(false));
    9589           6 :     already_done = true;
    9590             : }
    9591             : 
    9592             : /*
    9593             :  * Get latest WAL insert pointer
    9594             :  */
    9595             : XLogRecPtr
    9596        4034 : GetXLogInsertRecPtr(void)
    9597             : {
    9598        4034 :     XLogCtlInsert *Insert = &XLogCtl->Insert;
    9599             :     uint64      current_bytepos;
    9600             : 
    9601        4034 :     SpinLockAcquire(&Insert->insertpos_lck);
    9602        4034 :     current_bytepos = Insert->CurrBytePos;
    9603        4034 :     SpinLockRelease(&Insert->insertpos_lck);
    9604             : 
    9605        4034 :     return XLogBytePosToRecPtr(current_bytepos);
    9606             : }
    9607             : 
    9608             : /*
    9609             :  * Get latest WAL write pointer
    9610             :  */
    9611             : XLogRecPtr
    9612       11854 : GetXLogWriteRecPtr(void)
    9613             : {
    9614       11854 :     RefreshXLogWriteResult(LogwrtResult);
    9615             : 
    9616       11854 :     return LogwrtResult.Write;
    9617             : }
    9618             : 
    9619             : /*
    9620             :  * Returns the redo pointer of the last checkpoint or restartpoint. This is
    9621             :  * the oldest point in WAL that we still need, if we have to restart recovery.
    9622             :  */
    9623             : void
    9624         790 : GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
    9625             : {
    9626         790 :     LWLockAcquire(ControlFileLock, LW_SHARED);
    9627         790 :     *oldrecptr = ControlFile->checkPointCopy.redo;
    9628         790 :     *oldtli = ControlFile->checkPointCopy.ThisTimeLineID;
    9629         790 :     LWLockRelease(ControlFileLock);
    9630         790 : }
    9631             : 
    9632             : /* Thin wrapper around ShutdownWalRcv(). */
    9633             : void
    9634        1978 : XLogShutdownWalRcv(void)
    9635             : {
    9636             :     Assert(AmStartupProcess() || !IsUnderPostmaster);
    9637             : 
    9638        1978 :     ShutdownWalRcv();
    9639        1978 :     ResetInstallXLogFileSegmentActive();
    9640        1978 : }
    9641             : 
    9642             : /* Enable WAL file recycling and preallocation. */
    9643             : void
    9644        2368 : SetInstallXLogFileSegmentActive(void)
    9645             : {
    9646        2368 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    9647        2368 :     XLogCtl->InstallXLogFileSegmentActive = true;
    9648        2368 :     LWLockRelease(ControlFileLock);
    9649        2368 : }
    9650             : 
    9651             : /* Disable WAL file recycling and preallocation. */
    9652             : void
    9653        2290 : ResetInstallXLogFileSegmentActive(void)
    9654             : {
    9655        2290 :     LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
    9656        2290 :     XLogCtl->InstallXLogFileSegmentActive = false;
    9657        2290 :     LWLockRelease(ControlFileLock);
    9658        2290 : }
    9659             : 
    9660             : bool
    9661           0 : IsInstallXLogFileSegmentActive(void)
    9662             : {
    9663             :     bool        result;
    9664             : 
    9665           0 :     LWLockAcquire(ControlFileLock, LW_SHARED);
    9666           0 :     result = XLogCtl->InstallXLogFileSegmentActive;
    9667           0 :     LWLockRelease(ControlFileLock);
    9668             : 
    9669           0 :     return result;
    9670             : }
    9671             : 
    9672             : /*
    9673             :  * Update the WalWriterSleeping flag.
    9674             :  */
    9675             : void
    9676        1040 : SetWalWriterSleeping(bool sleeping)
    9677             : {
    9678        1040 :     SpinLockAcquire(&XLogCtl->info_lck);
    9679        1040 :     XLogCtl->WalWriterSleeping = sleeping;
    9680        1040 :     SpinLockRelease(&XLogCtl->info_lck);
    9681        1040 : }

Generated by: LCOV version 1.16