LCOV - code coverage report
Current view: top level - src/backend/access/transam - timeline.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 80.8 % 198 160
Test Date: 2026-10-29 00:16:02 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 48.8 % 170 83

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * timeline.c
       4                 :             :  *      Functions for reading and writing timeline history files.
       5                 :             :  *
       6                 :             :  * A timeline history file lists the timeline changes of the timeline, in
       7                 :             :  * a simple text format. They are archived along with the WAL segments.
       8                 :             :  *
       9                 :             :  * The files are named like "<tli>.history". For example, if the database
      10                 :             :  * starts up and switches to timeline 5, the timeline history file would be
      11                 :             :  * called "00000005.history".
      12                 :             :  *
      13                 :             :  * Each line in the file represents a timeline switch:
      14                 :             :  *
      15                 :             :  * <parentTLI> <switchpoint> <reason>
      16                 :             :  *
      17                 :             :  *  parentTLI   ID of the parent timeline
      18                 :             :  *  switchpoint XLogRecPtr of the WAL location where the switch happened
      19                 :             :  *  reason      human-readable explanation of why the timeline was changed
      20                 :             :  *
      21                 :             :  * The fields are separated by tabs. Lines beginning with # are comments, and
      22                 :             :  * are ignored. Empty lines are also ignored.
      23                 :             :  *
      24                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      25                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      26                 :             :  *
      27                 :             :  * src/backend/access/transam/timeline.c
      28                 :             :  *
      29                 :             :  *-------------------------------------------------------------------------
      30                 :             :  */
      31                 :             : 
      32                 :             : #include "postgres.h"
      33                 :             : 
      34                 :             : #include <sys/stat.h>
      35                 :             : #include <unistd.h>
      36                 :             : 
      37                 :             : #include "access/timeline.h"
      38                 :             : #include "access/xlog.h"
      39                 :             : #include "access/xlog_internal.h"
      40                 :             : #include "access/xlogarchive.h"
      41                 :             : #include "access/xlogdefs.h"
      42                 :             : #include "common/pg_parse_lsn.h"
      43                 :             : #include "pgstat.h"
      44                 :             : #include "storage/fd.h"
      45                 :             : #include "utils/wait_event.h"
      46                 :             : 
      47                 :             : /*
      48                 :             :  * Copies all timeline history files with id's between 'begin' and 'end'
      49                 :             :  * from archive to pg_wal.
      50                 :             :  */
      51                 :             : void
      52                 :        1159 : restoreTimeLineHistoryFiles(TimeLineID begin, TimeLineID end)
      53                 :             : {
      54                 :             :     char        path[MAXPGPATH];
      55                 :             :     char        histfname[MAXFNAMELEN];
      56                 :             :     TimeLineID  tli;
      57                 :             : 
      58         [ +  + ]:        1168 :     for (tli = begin; tli < end; tli++)
      59                 :             :     {
      60         [ +  + ]:           9 :         if (tli == 1)
      61                 :           6 :             continue;
      62                 :             : 
      63                 :           3 :         TLHistoryFileName(histfname, tli);
      64         [ +  + ]:           3 :         if (RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false))
      65                 :           1 :             KeepFileRestoredFromArchive(path, histfname);
      66                 :             :     }
      67                 :        1159 : }
      68                 :             : 
      69                 :             : /*
      70                 :             :  * Try to read a timeline's history file.
      71                 :             :  *
      72                 :             :  * If successful, return the list of component TLIs (the given TLI followed by
      73                 :             :  * its ancestor TLIs).  If we can't find the history file, assume that the
      74                 :             :  * timeline has no parents, and return a list of just the specified timeline
      75                 :             :  * ID.
      76                 :             :  */
      77                 :             : List *
      78                 :        3058 : readTimeLineHistory(TimeLineID targetTLI)
      79                 :             : {
      80                 :             :     List       *result;
      81                 :             :     char        path[MAXPGPATH];
      82                 :             :     char        histfname[MAXFNAMELEN];
      83                 :             :     FILE       *fd;
      84                 :             :     TimeLineHistoryEntry *entry;
      85                 :        3058 :     TimeLineID  lasttli = 0;
      86                 :             :     XLogRecPtr  prevend;
      87                 :        3058 :     bool        fromArchive = false;
      88                 :             : 
      89                 :             :     /* Timeline 1 does not have a history file, so no need to check */
      90         [ +  + ]:        3058 :     if (targetTLI == 1)
      91                 :             :     {
      92                 :        2945 :         entry = palloc_object(TimeLineHistoryEntry);
      93                 :        2945 :         entry->tli = targetTLI;
      94                 :        2945 :         entry->begin = entry->end = InvalidXLogRecPtr;
      95                 :        2945 :         return list_make1(entry);
      96                 :             :     }
      97                 :             : 
      98         [ +  + ]:         113 :     if (ArchiveRecoveryRequested)
      99                 :             :     {
     100                 :          47 :         TLHistoryFileName(histfname, targetTLI);
     101                 :             :         fromArchive =
     102                 :          47 :             RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
     103                 :             :     }
     104                 :             :     else
     105                 :          66 :         TLHistoryFilePath(path, targetTLI);
     106                 :             : 
     107                 :         113 :     fd = AllocateFile(path, "r");
     108         [ -  + ]:         113 :     if (fd == NULL)
     109                 :             :     {
     110         [ #  # ]:           0 :         if (errno != ENOENT)
     111         [ #  # ]:           0 :             ereport(FATAL,
     112                 :             :                     (errcode_for_file_access(),
     113                 :             :                      errmsg("could not open file \"%s\": %m", path)));
     114                 :             :         /* Not there, so assume no parents */
     115                 :           0 :         entry = palloc_object(TimeLineHistoryEntry);
     116                 :           0 :         entry->tli = targetTLI;
     117                 :           0 :         entry->begin = entry->end = InvalidXLogRecPtr;
     118                 :           0 :         return list_make1(entry);
     119                 :             :     }
     120                 :             : 
     121                 :         113 :     result = NIL;
     122                 :             : 
     123                 :             :     /*
     124                 :             :      * Parse the file...
     125                 :             :      */
     126                 :         113 :     prevend = InvalidXLogRecPtr;
     127                 :             :     for (;;)
     128                 :         285 :     {
     129                 :             :         char        fline[MAXPGPATH];
     130                 :             :         char       *res;
     131                 :             :         char       *ptr;
     132                 :             :         char       *token_end;
     133                 :             :         char        save;
     134                 :             :         TimeLineID  tli;
     135                 :             :         XLogRecPtr  switchpoint;
     136                 :         398 :         bool        valid_switchpoint = false;
     137                 :             :         int         nchars;
     138                 :             :         size_t      nspaces;
     139                 :             : 
     140                 :         398 :         pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_READ);
     141                 :         398 :         res = fgets(fline, sizeof(fline), fd);
     142                 :         398 :         pgstat_report_wait_end();
     143         [ +  + ]:         398 :         if (res == NULL)
     144                 :             :         {
     145         [ -  + ]:         113 :             if (ferror(fd))
     146         [ #  # ]:           0 :                 ereport(ERROR,
     147                 :             :                         (errcode_for_file_access(),
     148                 :             :                          errmsg("could not read file \"%s\": %m", path)));
     149                 :             : 
     150                 :         113 :             break;
     151                 :             :         }
     152                 :             : 
     153                 :             :         /* skip leading whitespace and check for # comment */
     154         [ +  + ]:         374 :         for (ptr = fline; *ptr; ptr++)
     155                 :             :         {
     156         [ +  + ]:         285 :             if (!isspace((unsigned char) *ptr))
     157                 :         196 :                 break;
     158                 :             :         }
     159   [ +  +  -  + ]:         285 :         if (*ptr == '\0' || *ptr == '#')
     160                 :          89 :             continue;
     161                 :             : 
     162         [ -  + ]:         196 :         if (sscanf(fline, "%u%n", &tli, &nchars) != 1)
     163                 :             :         {
     164                 :             :             /* expect a numeric timeline ID as first field of line */
     165         [ #  # ]:           0 :             ereport(FATAL,
     166                 :             :                     (errmsg("syntax error in history file: %s", fline),
     167                 :             :                      errhint("Expected a numeric timeline ID.")));
     168                 :             :         }
     169                 :             : 
     170                 :             :         /* the switchpoint location follows, separated by whitespace */
     171                 :         196 :         ptr = fline + nchars;
     172                 :         196 :         nspaces = strspn(ptr, " \t\n\r\f\v");
     173         [ +  - ]:         196 :         if (nspaces > 0)
     174                 :             :         {
     175                 :         196 :             ptr += nspaces;
     176                 :             : 
     177                 :             :             /*
     178                 :             :              * isolate the location from the rest of the line before parsing
     179                 :             :              * it
     180                 :             :              */
     181                 :         196 :             token_end = ptr + strcspn(ptr, " \t\n\r\f\v");
     182                 :         196 :             save = *token_end;
     183                 :         196 :             *token_end = '\0';
     184                 :         196 :             valid_switchpoint = pg_parse_lsn(ptr, &switchpoint);
     185                 :         196 :             *token_end = save;
     186                 :             :         }
     187                 :             : 
     188         [ -  + ]:         196 :         if (!valid_switchpoint)
     189         [ #  # ]:           0 :             ereport(FATAL,
     190                 :             :                     (errmsg("syntax error in history file: %s", fline),
     191                 :             :                      errhint("Expected a write-ahead log switchpoint location.")));
     192                 :             : 
     193   [ +  +  -  + ]:         196 :         if (result && tli <= lasttli)
     194         [ #  # ]:           0 :             ereport(FATAL,
     195                 :             :                     (errmsg("invalid data in history file: %s", fline),
     196                 :             :                      errhint("Timeline IDs must be in increasing sequence.")));
     197                 :             : 
     198                 :         196 :         lasttli = tli;
     199                 :             : 
     200                 :         196 :         entry = palloc_object(TimeLineHistoryEntry);
     201                 :         196 :         entry->tli = tli;
     202                 :         196 :         entry->begin = prevend;
     203                 :         196 :         entry->end = switchpoint;
     204                 :         196 :         prevend = entry->end;
     205                 :             : 
     206                 :             :         /* Build list with newest item first */
     207                 :         196 :         result = lcons(entry, result);
     208                 :             : 
     209                 :             :         /* we ignore the remainder of each line */
     210                 :             :     }
     211                 :             : 
     212                 :         113 :     FreeFile(fd);
     213                 :             : 
     214   [ +  -  -  + ]:         113 :     if (result && targetTLI <= lasttli)
     215         [ #  # ]:           0 :         ereport(FATAL,
     216                 :             :                 (errmsg("invalid data in history file \"%s\"", path),
     217                 :             :                  errhint("Timeline IDs must be less than child timeline's ID.")));
     218                 :             : 
     219                 :             :     /*
     220                 :             :      * Create one more entry for the "tip" of the timeline, which has no entry
     221                 :             :      * in the history file.
     222                 :             :      */
     223                 :         113 :     entry = palloc_object(TimeLineHistoryEntry);
     224                 :         113 :     entry->tli = targetTLI;
     225                 :         113 :     entry->begin = prevend;
     226                 :         113 :     entry->end = InvalidXLogRecPtr;
     227                 :             : 
     228                 :         113 :     result = lcons(entry, result);
     229                 :             : 
     230                 :             :     /*
     231                 :             :      * If the history file was fetched from archive, save it in pg_wal for
     232                 :             :      * future reference.
     233                 :             :      */
     234         [ +  + ]:         113 :     if (fromArchive)
     235                 :           3 :         KeepFileRestoredFromArchive(path, histfname);
     236                 :             : 
     237                 :         113 :     return result;
     238                 :             : }
     239                 :             : 
     240                 :             : /*
     241                 :             :  * Probe whether a timeline history file exists for the given timeline ID
     242                 :             :  */
     243                 :             : bool
     244                 :         499 : existsTimeLineHistory(TimeLineID probeTLI)
     245                 :             : {
     246                 :             :     char        path[MAXPGPATH];
     247                 :             :     char        histfname[MAXFNAMELEN];
     248                 :             :     FILE       *fd;
     249                 :             : 
     250                 :             :     /* Timeline 1 does not have a history file, so no need to check */
     251         [ -  + ]:         499 :     if (probeTLI == 1)
     252                 :           0 :         return false;
     253                 :             : 
     254         [ +  + ]:         499 :     if (ArchiveRecoveryRequested)
     255                 :             :     {
     256                 :         447 :         TLHistoryFileName(histfname, probeTLI);
     257                 :         447 :         RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
     258                 :             :     }
     259                 :             :     else
     260                 :          52 :         TLHistoryFilePath(path, probeTLI);
     261                 :             : 
     262                 :         498 :     fd = AllocateFile(path, "r");
     263         [ +  + ]:         498 :     if (fd != NULL)
     264                 :             :     {
     265                 :          53 :         FreeFile(fd);
     266                 :          53 :         return true;
     267                 :             :     }
     268                 :             :     else
     269                 :             :     {
     270         [ -  + ]:         445 :         if (errno != ENOENT)
     271         [ #  # ]:           0 :             ereport(FATAL,
     272                 :             :                     (errcode_for_file_access(),
     273                 :             :                      errmsg("could not open file \"%s\": %m", path)));
     274                 :         445 :         return false;
     275                 :             :     }
     276                 :             : }
     277                 :             : 
     278                 :             : /*
     279                 :             :  * Find the newest existing timeline, assuming that startTLI exists.
     280                 :             :  *
     281                 :             :  * Note: while this is somewhat heuristic, it does positively guarantee
     282                 :             :  * that (result + 1) is not a known timeline, and therefore it should
     283                 :             :  * be safe to assign that ID to a new timeline.
     284                 :             :  */
     285                 :             : TimeLineID
     286                 :         433 : findNewestTimeLine(TimeLineID startTLI)
     287                 :             : {
     288                 :             :     TimeLineID  newestTLI;
     289                 :             :     TimeLineID  probeTLI;
     290                 :             : 
     291                 :             :     /*
     292                 :             :      * The algorithm is just to probe for the existence of timeline history
     293                 :             :      * files.  XXX is it useful to allow gaps in the sequence?
     294                 :             :      */
     295                 :         433 :     newestTLI = startTLI;
     296                 :             : 
     297                 :         433 :     for (probeTLI = startTLI + 1;; probeTLI++)
     298                 :             :     {
     299         [ +  + ]:         447 :         if (existsTimeLineHistory(probeTLI))
     300                 :             :         {
     301                 :          14 :             newestTLI = probeTLI;   /* probeTLI exists */
     302                 :             :         }
     303                 :             :         else
     304                 :             :         {
     305                 :             :             /* doesn't exist, assume we're done */
     306                 :         432 :             break;
     307                 :             :         }
     308                 :             :     }
     309                 :             : 
     310                 :         432 :     return newestTLI;
     311                 :             : }
     312                 :             : 
     313                 :             : /*
     314                 :             :  * Create a new timeline history file.
     315                 :             :  *
     316                 :             :  *  newTLI: ID of the new timeline
     317                 :             :  *  parentTLI: ID of its immediate parent
     318                 :             :  *  switchpoint: WAL location where the system switched to the new timeline
     319                 :             :  *  reason: human-readable explanation of why the timeline was switched
     320                 :             :  *
     321                 :             :  * Currently this is only used at the end recovery, and so there are no locking
     322                 :             :  * considerations.  But we should be just as tense as XLogFileInit to avoid
     323                 :             :  * emplacing a bogus file.
     324                 :             :  */
     325                 :             : void
     326                 :          65 : writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
     327                 :             :                      XLogRecPtr switchpoint, const char *reason)
     328                 :             : {
     329                 :             :     char        path[MAXPGPATH];
     330                 :             :     char        tmppath[MAXPGPATH];
     331                 :             :     char        histfname[MAXFNAMELEN];
     332                 :             :     char        buffer[BLCKSZ];
     333                 :             :     int         srcfd;
     334                 :             :     int         fd;
     335                 :             :     ssize_t     nbytes;
     336                 :             : 
     337                 :             :     Assert(newTLI > parentTLI); /* else bad selection of newTLI */
     338                 :             : 
     339                 :             :     /*
     340                 :             :      * Write into a temp file name.
     341                 :             :      */
     342                 :          65 :     snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
     343                 :             : 
     344                 :          65 :     unlink(tmppath);
     345                 :             : 
     346                 :             :     /* do not use get_sync_bit() here --- want to fsync only at end of fill */
     347                 :          65 :     fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL);
     348         [ -  + ]:          65 :     if (fd < 0)
     349         [ #  # ]:           0 :         ereport(ERROR,
     350                 :             :                 (errcode_for_file_access(),
     351                 :             :                  errmsg("could not create file \"%s\": %m", tmppath)));
     352                 :             : 
     353                 :             :     /*
     354                 :             :      * If a history file exists for the parent, copy it verbatim
     355                 :             :      */
     356         [ +  - ]:          65 :     if (ArchiveRecoveryRequested)
     357                 :             :     {
     358                 :          65 :         TLHistoryFileName(histfname, parentTLI);
     359                 :          65 :         RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
     360                 :             :     }
     361                 :             :     else
     362                 :           0 :         TLHistoryFilePath(path, parentTLI);
     363                 :             : 
     364                 :          65 :     srcfd = OpenTransientFile(path, O_RDONLY);
     365         [ +  + ]:          65 :     if (srcfd < 0)
     366                 :             :     {
     367         [ -  + ]:          56 :         if (errno != ENOENT)
     368         [ #  # ]:           0 :             ereport(ERROR,
     369                 :             :                     (errcode_for_file_access(),
     370                 :             :                      errmsg("could not open file \"%s\": %m", path)));
     371                 :             :         /* Not there, so assume parent has no parents */
     372                 :             :     }
     373                 :             :     else
     374                 :             :     {
     375                 :             :         for (;;)
     376                 :             :         {
     377                 :           9 :             errno = 0;
     378                 :          18 :             pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_READ);
     379                 :          18 :             nbytes = read(srcfd, buffer, sizeof(buffer));
     380                 :          18 :             pgstat_report_wait_end();
     381   [ +  -  -  + ]:          18 :             if (nbytes < 0 || errno != 0)
     382         [ #  # ]:           0 :                 ereport(ERROR,
     383                 :             :                         (errcode_for_file_access(),
     384                 :             :                          errmsg("could not read file \"%s\": %m", path)));
     385         [ +  + ]:          18 :             if (nbytes == 0)
     386                 :           9 :                 break;
     387                 :           9 :             errno = 0;
     388                 :           9 :             pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_WRITE);
     389         [ -  + ]:           9 :             if (write(fd, buffer, nbytes) != nbytes)
     390                 :             :             {
     391                 :           0 :                 int         save_errno = errno;
     392                 :             : 
     393                 :             :                 /*
     394                 :             :                  * If we fail to make the file, delete it to release disk
     395                 :             :                  * space
     396                 :             :                  */
     397                 :           0 :                 unlink(tmppath);
     398                 :             : 
     399                 :             :                 /*
     400                 :             :                  * if write didn't set errno, assume problem is no disk space
     401                 :             :                  */
     402         [ #  # ]:           0 :                 errno = save_errno ? save_errno : ENOSPC;
     403                 :             : 
     404         [ #  # ]:           0 :                 ereport(ERROR,
     405                 :             :                         (errcode_for_file_access(),
     406                 :             :                          errmsg("could not write to file \"%s\": %m", tmppath)));
     407                 :             :             }
     408                 :           9 :             pgstat_report_wait_end();
     409                 :             :         }
     410                 :             : 
     411         [ -  + ]:           9 :         if (CloseTransientFile(srcfd) != 0)
     412         [ #  # ]:           0 :             ereport(ERROR,
     413                 :             :                     (errcode_for_file_access(),
     414                 :             :                      errmsg("could not close file \"%s\": %m", path)));
     415                 :             :     }
     416                 :             : 
     417                 :             :     /*
     418                 :             :      * Append one line with the details of this timeline split.
     419                 :             :      *
     420                 :             :      * If we did have a parent file, insert an extra newline just in case the
     421                 :             :      * parent file failed to end with one.
     422                 :             :      */
     423                 :          65 :     snprintf(buffer, sizeof(buffer),
     424                 :             :              "%s%u\t%X/%08X\t%s\n",
     425                 :             :              (srcfd < 0) ? "" : "\n",
     426                 :             :              parentTLI,
     427         [ +  + ]:          65 :              LSN_FORMAT_ARGS(switchpoint),
     428                 :             :              reason);
     429                 :             : 
     430                 :          65 :     nbytes = strlen(buffer);
     431                 :          65 :     errno = 0;
     432                 :          65 :     pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_WRITE);
     433         [ -  + ]:          65 :     if (write(fd, buffer, nbytes) != nbytes)
     434                 :             :     {
     435                 :           0 :         int         save_errno = errno;
     436                 :             : 
     437                 :             :         /*
     438                 :             :          * If we fail to make the file, delete it to release disk space
     439                 :             :          */
     440                 :           0 :         unlink(tmppath);
     441                 :             :         /* if write didn't set errno, assume problem is no disk space */
     442         [ #  # ]:           0 :         errno = save_errno ? save_errno : ENOSPC;
     443                 :             : 
     444         [ #  # ]:           0 :         ereport(ERROR,
     445                 :             :                 (errcode_for_file_access(),
     446                 :             :                  errmsg("could not write to file \"%s\": %m", tmppath)));
     447                 :             :     }
     448                 :          65 :     pgstat_report_wait_end();
     449                 :             : 
     450                 :          65 :     pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_SYNC);
     451         [ -  + ]:          65 :     if (pg_fsync(fd) != 0)
     452         [ #  # ]:           0 :         ereport(data_sync_elevel(ERROR),
     453                 :             :                 (errcode_for_file_access(),
     454                 :             :                  errmsg("could not fsync file \"%s\": %m", tmppath)));
     455                 :          65 :     pgstat_report_wait_end();
     456                 :             : 
     457         [ -  + ]:          65 :     if (CloseTransientFile(fd) != 0)
     458         [ #  # ]:           0 :         ereport(ERROR,
     459                 :             :                 (errcode_for_file_access(),
     460                 :             :                  errmsg("could not close file \"%s\": %m", tmppath)));
     461                 :             : 
     462                 :             :     /*
     463                 :             :      * Now move the completed history file into place with its final name.
     464                 :             :      */
     465                 :          65 :     TLHistoryFilePath(path, newTLI);
     466                 :             :     Assert(access(path, F_OK) != 0 && errno == ENOENT);
     467                 :          65 :     durable_rename(tmppath, path, ERROR);
     468                 :             : 
     469                 :             :     /* The history file can be archived immediately. */
     470         [ +  + ]:          65 :     if (XLogArchivingActive())
     471                 :             :     {
     472                 :          16 :         TLHistoryFileName(histfname, newTLI);
     473                 :          16 :         XLogArchiveNotify(histfname);
     474                 :             :     }
     475                 :          65 : }
     476                 :             : 
     477                 :             : /*
     478                 :             :  * Writes a history file for given timeline and contents.
     479                 :             :  *
     480                 :             :  * Currently this is only used in the walreceiver process, and so there are
     481                 :             :  * no locking considerations.  But we should be just as tense as XLogFileInit
     482                 :             :  * to avoid emplacing a bogus file.
     483                 :             :  */
     484                 :             : void
     485                 :          13 : writeTimeLineHistoryFile(TimeLineID tli, const char *content, size_t size)
     486                 :             : {
     487                 :             :     char        path[MAXPGPATH];
     488                 :             :     char        tmppath[MAXPGPATH];
     489                 :             :     int         fd;
     490                 :             : 
     491                 :             :     /*
     492                 :             :      * Write into a temp file name.
     493                 :             :      */
     494                 :          13 :     snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
     495                 :             : 
     496                 :          13 :     unlink(tmppath);
     497                 :             : 
     498                 :             :     /* do not use get_sync_bit() here --- want to fsync only at end of fill */
     499                 :          13 :     fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL);
     500         [ -  + ]:          13 :     if (fd < 0)
     501         [ #  # ]:           0 :         ereport(ERROR,
     502                 :             :                 (errcode_for_file_access(),
     503                 :             :                  errmsg("could not create file \"%s\": %m", tmppath)));
     504                 :             : 
     505                 :          13 :     errno = 0;
     506                 :          13 :     pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE);
     507         [ -  + ]:          13 :     if (write(fd, content, size) != size)
     508                 :             :     {
     509                 :           0 :         int         save_errno = errno;
     510                 :             : 
     511                 :             :         /*
     512                 :             :          * If we fail to make the file, delete it to release disk space
     513                 :             :          */
     514                 :           0 :         unlink(tmppath);
     515                 :             :         /* if write didn't set errno, assume problem is no disk space */
     516         [ #  # ]:           0 :         errno = save_errno ? save_errno : ENOSPC;
     517                 :             : 
     518         [ #  # ]:           0 :         ereport(ERROR,
     519                 :             :                 (errcode_for_file_access(),
     520                 :             :                  errmsg("could not write to file \"%s\": %m", tmppath)));
     521                 :             :     }
     522                 :          13 :     pgstat_report_wait_end();
     523                 :             : 
     524                 :          13 :     pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC);
     525         [ -  + ]:          13 :     if (pg_fsync(fd) != 0)
     526         [ #  # ]:           0 :         ereport(data_sync_elevel(ERROR),
     527                 :             :                 (errcode_for_file_access(),
     528                 :             :                  errmsg("could not fsync file \"%s\": %m", tmppath)));
     529                 :          13 :     pgstat_report_wait_end();
     530                 :             : 
     531         [ -  + ]:          13 :     if (CloseTransientFile(fd) != 0)
     532         [ #  # ]:           0 :         ereport(ERROR,
     533                 :             :                 (errcode_for_file_access(),
     534                 :             :                  errmsg("could not close file \"%s\": %m", tmppath)));
     535                 :             : 
     536                 :             :     /*
     537                 :             :      * Now move the completed history file into place with its final name,
     538                 :             :      * replacing any existing file with the same name.
     539                 :             :      */
     540                 :          13 :     TLHistoryFilePath(path, tli);
     541                 :          13 :     durable_rename(tmppath, path, ERROR);
     542                 :          13 : }
     543                 :             : 
     544                 :             : /*
     545                 :             :  * Returns true if 'expectedTLEs' contains a timeline with id 'tli'
     546                 :             :  */
     547                 :             : bool
     548                 :     2933496 : tliInHistory(TimeLineID tli, List *expectedTLEs)
     549                 :             : {
     550                 :             :     ListCell   *cell;
     551                 :             : 
     552   [ +  -  +  -  :     2945075 :     foreach(cell, expectedTLEs)
                   +  - ]
     553                 :             :     {
     554         [ +  + ]:     2945075 :         if (((TimeLineHistoryEntry *) lfirst(cell))->tli == tli)
     555                 :     2933496 :             return true;
     556                 :             :     }
     557                 :             : 
     558                 :           0 :     return false;
     559                 :             : }
     560                 :             : 
     561                 :             : /*
     562                 :             :  * Returns the ID of the timeline in use at a particular point in time, in
     563                 :             :  * the given timeline history.
     564                 :             :  */
     565                 :             : TimeLineID
     566                 :        3103 : tliOfPointInHistory(XLogRecPtr ptr, List *history)
     567                 :             : {
     568                 :             :     ListCell   *cell;
     569                 :             : 
     570   [ +  -  +  -  :        3117 :     foreach(cell, history)
                   +  - ]
     571                 :             :     {
     572                 :        3117 :         TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
     573                 :             : 
     574   [ +  +  +  + ]:        3117 :         if ((!XLogRecPtrIsValid(tle->begin) || tle->begin <= ptr) &&
     575   [ +  +  +  - ]:        3103 :             (!XLogRecPtrIsValid(tle->end) || ptr < tle->end))
     576                 :             :         {
     577                 :             :             /* found it */
     578                 :        3103 :             return tle->tli;
     579                 :             :         }
     580                 :             :     }
     581                 :             : 
     582                 :             :     /* shouldn't happen. */
     583         [ #  # ]:           0 :     elog(ERROR, "timeline history was not contiguous");
     584                 :             :     return 0;                   /* keep compiler quiet */
     585                 :             : }
     586                 :             : 
     587                 :             : /*
     588                 :             :  * Returns the point in history where we branched off the given timeline,
     589                 :             :  * and the timeline we branched to (*nextTLI). Returns InvalidXLogRecPtr if
     590                 :             :  * the timeline is current, ie. we have not branched off from it, and throws
     591                 :             :  * an error if the timeline is not part of this server's history.
     592                 :             :  */
     593                 :             : XLogRecPtr
     594                 :        1685 : tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
     595                 :             : {
     596                 :             :     ListCell   *cell;
     597                 :             : 
     598         [ +  - ]:        1685 :     if (nextTLI)
     599                 :        1685 :         *nextTLI = 0;
     600   [ +  -  +  -  :        1700 :     foreach(cell, history)
                   +  - ]
     601                 :             :     {
     602                 :        1700 :         TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
     603                 :             : 
     604         [ +  + ]:        1700 :         if (tle->tli == tli)
     605                 :        1685 :             return tle->end;
     606         [ +  - ]:          15 :         if (nextTLI)
     607                 :          15 :             *nextTLI = tle->tli;
     608                 :             :     }
     609                 :             : 
     610         [ #  # ]:           0 :     ereport(ERROR,
     611                 :             :             (errmsg("requested timeline %u is not in this server's history",
     612                 :             :                     tli)));
     613                 :             :     return InvalidXLogRecPtr;   /* keep compiler quiet */
     614                 :             : }
        

Generated by: LCOV version 2.0-1