LCOV - differential code coverage report
Current view: top level - src/backend/backup - walsummary.c (source / functions) Coverage Total Hit UNC GNC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 72.4 % 105 76 29 76
Current Date: 2024-04-14 14:21:10 Functions: 90.0 % 10 9 1 9
Baseline: 16@8cea358b128 Branches: 44.4 % 90 40 50 40
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 100.0 % 1 1 1
(60,120] days: 72.1 % 104 75 29 75
Function coverage date bins:
(60,120] days: 90.0 % 10 9 1 9
Branch coverage date bins:
(60,120] days: 44.4 % 90 40 50 40

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * walsummary.c
                                  4                 :                :  *    Functions for accessing and managing WAL summary data.
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 2010-2024, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  * src/backend/backup/walsummary.c
                                  9                 :                :  *
                                 10                 :                :  *-------------------------------------------------------------------------
                                 11                 :                :  */
                                 12                 :                : 
                                 13                 :                : #include "postgres.h"
                                 14                 :                : 
                                 15                 :                : #include <sys/stat.h>
                                 16                 :                : #include <unistd.h>
                                 17                 :                : 
                                 18                 :                : #include "access/xlog_internal.h"
                                 19                 :                : #include "backup/walsummary.h"
                                 20                 :                : #include "common/int.h"
                                 21                 :                : #include "utils/wait_event.h"
                                 22                 :                : 
                                 23                 :                : static bool IsWalSummaryFilename(char *filename);
                                 24                 :                : static int  ListComparatorForWalSummaryFiles(const ListCell *a,
                                 25                 :                :                                              const ListCell *b);
                                 26                 :                : 
                                 27                 :                : /*
                                 28                 :                :  * Get a list of WAL summaries.
                                 29                 :                :  *
                                 30                 :                :  * If tli != 0, only WAL summaries with the indicated TLI will be included.
                                 31                 :                :  *
                                 32                 :                :  * If start_lsn != InvalidXLogRecPtr, only summaries that end after the
                                 33                 :                :  * indicated LSN will be included.
                                 34                 :                :  *
                                 35                 :                :  * If end_lsn != InvalidXLogRecPtr, only summaries that start before the
                                 36                 :                :  * indicated LSN will be included.
                                 37                 :                :  *
                                 38                 :                :  * The intent is that you can call GetWalSummaries(tli, start_lsn, end_lsn)
                                 39                 :                :  * to get all WAL summaries on the indicated timeline that overlap the
                                 40                 :                :  * specified LSN range.
                                 41                 :                :  */
                                 42                 :                : List *
  116 rhaas@postgresql.org       43                 :GNC          56 : GetWalSummaries(TimeLineID tli, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
                                 44                 :                : {
                                 45                 :                :     DIR        *sdir;
                                 46                 :                :     struct dirent *dent;
                                 47                 :             56 :     List       *result = NIL;
                                 48                 :                : 
                                 49                 :             56 :     sdir = AllocateDir(XLOGDIR "/summaries");
                                 50         [ +  + ]:            415 :     while ((dent = ReadDir(sdir, XLOGDIR "/summaries")) != NULL)
                                 51                 :                :     {
                                 52                 :                :         WalSummaryFile *ws;
                                 53                 :                :         uint32      tmp[5];
                                 54                 :                :         TimeLineID  file_tli;
                                 55                 :                :         XLogRecPtr  file_start_lsn;
                                 56                 :                :         XLogRecPtr  file_end_lsn;
                                 57                 :                : 
                                 58                 :                :         /* Decode filename, or skip if it's not in the expected format. */
                                 59         [ +  + ]:            359 :         if (!IsWalSummaryFilename(dent->d_name))
                                 60                 :            157 :             continue;
                                 61                 :            247 :         sscanf(dent->d_name, "%08X%08X%08X%08X%08X",
                                 62                 :                :                &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4]);
                                 63                 :            247 :         file_tli = tmp[0];
                                 64                 :            247 :         file_start_lsn = ((uint64) tmp[1]) << 32 | tmp[2];
                                 65                 :            247 :         file_end_lsn = ((uint64) tmp[3]) << 32 | tmp[4];
                                 66                 :                : 
                                 67                 :                :         /* Skip if it doesn't match the filter criteria. */
                                 68   [ -  +  -  - ]:            247 :         if (tli != 0 && tli != file_tli)
  116 rhaas@postgresql.org       69                 :UNC           0 :             continue;
  116 rhaas@postgresql.org       70   [ +  +  +  + ]:GNC         247 :         if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn >= file_end_lsn)
                                 71                 :             45 :             continue;
                                 72   [ +  +  -  + ]:            202 :         if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn <= file_start_lsn)
  116 rhaas@postgresql.org       73                 :UNC           0 :             continue;
                                 74                 :                : 
                                 75                 :                :         /* Add it to the list. */
  116 rhaas@postgresql.org       76                 :GNC         202 :         ws = palloc(sizeof(WalSummaryFile));
                                 77                 :            202 :         ws->tli = file_tli;
                                 78                 :            202 :         ws->start_lsn = file_start_lsn;
                                 79                 :            202 :         ws->end_lsn = file_end_lsn;
                                 80                 :            202 :         result = lappend(result, ws);
                                 81                 :                :     }
                                 82                 :             56 :     FreeDir(sdir);
                                 83                 :                : 
                                 84                 :             56 :     return result;
                                 85                 :                : }
                                 86                 :                : 
                                 87                 :                : /*
                                 88                 :                :  * Build a new list of WAL summaries based on an existing list, but filtering
                                 89                 :                :  * out summaries that don't match the search parameters.
                                 90                 :                :  *
                                 91                 :                :  * If tli != 0, only WAL summaries with the indicated TLI will be included.
                                 92                 :                :  *
                                 93                 :                :  * If start_lsn != InvalidXLogRecPtr, only summaries that end after the
                                 94                 :                :  * indicated LSN will be included.
                                 95                 :                :  *
                                 96                 :                :  * If end_lsn != InvalidXLogRecPtr, only summaries that start before the
                                 97                 :                :  * indicated LSN will be included.
                                 98                 :                :  */
                                 99                 :                : List *
                                100                 :              7 : FilterWalSummaries(List *wslist, TimeLineID tli,
                                101                 :                :                    XLogRecPtr start_lsn, XLogRecPtr end_lsn)
                                102                 :                : {
                                103                 :              7 :     List       *result = NIL;
                                104                 :                :     ListCell   *lc;
                                105                 :                : 
                                106                 :                :     /* Loop over input. */
                                107   [ +  -  +  +  :             19 :     foreach(lc, wslist)
                                              +  + ]
                                108                 :                :     {
                                109                 :             12 :         WalSummaryFile *ws = lfirst(lc);
                                110                 :                : 
                                111                 :                :         /* Skip if it doesn't match the filter criteria. */
                                112   [ +  -  -  + ]:             12 :         if (tli != 0 && tli != ws->tli)
  116 rhaas@postgresql.org      113                 :UNC           0 :             continue;
  116 rhaas@postgresql.org      114   [ +  -  -  + ]:GNC          12 :         if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn > ws->end_lsn)
  116 rhaas@postgresql.org      115                 :UNC           0 :             continue;
  116 rhaas@postgresql.org      116   [ +  -  -  + ]:GNC          12 :         if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn < ws->start_lsn)
  116 rhaas@postgresql.org      117                 :UNC           0 :             continue;
                                118                 :                : 
                                119                 :                :         /* Add it to the result list. */
  116 rhaas@postgresql.org      120                 :GNC          12 :         result = lappend(result, ws);
                                121                 :                :     }
                                122                 :                : 
                                123                 :              7 :     return result;
                                124                 :                : }
                                125                 :                : 
                                126                 :                : /*
                                127                 :                :  * Check whether the supplied list of WalSummaryFile objects covers the
                                128                 :                :  * whole range of LSNs from start_lsn to end_lsn. This function ignores
                                129                 :                :  * timelines, so the caller should probably filter using the appropriate
                                130                 :                :  * timeline before calling this.
                                131                 :                :  *
                                132                 :                :  * If the whole range of LSNs is covered, returns true, otherwise false.
                                133                 :                :  * If false is returned, *missing_lsn is set either to InvalidXLogRecPtr
                                134                 :                :  * if there are no WAL summary files in the input list, or to the first LSN
                                135                 :                :  * in the range that is not covered by a WAL summary file in the input list.
                                136                 :                :  */
                                137                 :                : bool
                                138                 :              7 : WalSummariesAreComplete(List *wslist, XLogRecPtr start_lsn,
                                139                 :                :                         XLogRecPtr end_lsn, XLogRecPtr *missing_lsn)
                                140                 :                : {
                                141                 :              7 :     XLogRecPtr  current_lsn = start_lsn;
                                142                 :                :     ListCell   *lc;
                                143                 :                : 
                                144                 :                :     /* Special case for empty list. */
                                145         [ -  + ]:              7 :     if (wslist == NIL)
                                146                 :                :     {
  116 rhaas@postgresql.org      147                 :UNC           0 :         *missing_lsn = InvalidXLogRecPtr;
                                148                 :              0 :         return false;
                                149                 :                :     }
                                150                 :                : 
                                151                 :                :     /* Make a private copy of the list and sort it by start LSN. */
  116 rhaas@postgresql.org      152                 :GNC           7 :     wslist = list_copy(wslist);
                                153                 :              7 :     list_sort(wslist, ListComparatorForWalSummaryFiles);
                                154                 :                : 
                                155                 :                :     /*
                                156                 :                :      * Consider summary files in order of increasing start_lsn, advancing the
                                157                 :                :      * known-summarized range from start_lsn toward end_lsn.
                                158                 :                :      *
                                159                 :                :      * Normally, the summary files should cover non-overlapping WAL ranges,
                                160                 :                :      * but this algorithm is intended to be correct even in case of overlap.
                                161                 :                :      */
                                162   [ +  -  +  -  :             12 :     foreach(lc, wslist)
                                              +  - ]
                                163                 :                :     {
                                164                 :             12 :         WalSummaryFile *ws = lfirst(lc);
                                165                 :                : 
                                166         [ -  + ]:             12 :         if (ws->start_lsn > current_lsn)
                                167                 :                :         {
                                168                 :                :             /* We found a gap. */
  116 rhaas@postgresql.org      169                 :UNC           0 :             break;
                                170                 :                :         }
  116 rhaas@postgresql.org      171         [ +  - ]:GNC          12 :         if (ws->end_lsn > current_lsn)
                                172                 :                :         {
                                173                 :                :             /*
                                174                 :                :              * Next summary extends beyond end of previous summary, so extend
                                175                 :                :              * the end of the range known to be summarized.
                                176                 :                :              */
                                177                 :             12 :             current_lsn = ws->end_lsn;
                                178                 :                : 
                                179                 :                :             /*
                                180                 :                :              * If the range we know to be summarized has reached the required
                                181                 :                :              * end LSN, we have proved completeness.
                                182                 :                :              */
                                183         [ +  + ]:             12 :             if (current_lsn >= end_lsn)
                                184                 :              7 :                 return true;
                                185                 :                :         }
                                186                 :                :     }
                                187                 :                : 
                                188                 :                :     /*
                                189                 :                :      * We either ran out of summary files without reaching the end LSN, or we
                                190                 :                :      * hit a gap in the sequence that resulted in us bailing out of the loop
                                191                 :                :      * above.
                                192                 :                :      */
  116 rhaas@postgresql.org      193                 :UNC           0 :     *missing_lsn = current_lsn;
                                194                 :              0 :     return false;
                                195                 :                : }
                                196                 :                : 
                                197                 :                : /*
                                198                 :                :  * Open a WAL summary file.
                                199                 :                :  *
                                200                 :                :  * This will throw an error in case of trouble. As an exception, if
                                201                 :                :  * missing_ok = true and the trouble is specifically that the file does
                                202                 :                :  * not exist, it will not throw an error and will return a value less than 0.
                                203                 :                :  */
                                204                 :                : File
  116 rhaas@postgresql.org      205                 :GNC          12 : OpenWalSummaryFile(WalSummaryFile *ws, bool missing_ok)
                                206                 :                : {
                                207                 :                :     char        path[MAXPGPATH];
                                208                 :                :     File        file;
                                209                 :                : 
                                210                 :             12 :     snprintf(path, MAXPGPATH,
                                211                 :                :              XLOGDIR "/summaries/%08X%08X%08X%08X%08X.summary",
                                212                 :                :              ws->tli,
                                213                 :             12 :              LSN_FORMAT_ARGS(ws->start_lsn),
                                214                 :             12 :              LSN_FORMAT_ARGS(ws->end_lsn));
                                215                 :                : 
                                216                 :             12 :     file = PathNameOpenFile(path, O_RDONLY);
                                217   [ -  +  -  -  :             12 :     if (file < 0 && (errno != EEXIST || !missing_ok))
                                              -  - ]
  116 rhaas@postgresql.org      218         [ #  # ]:UNC           0 :         ereport(ERROR,
                                219                 :                :                 (errcode_for_file_access(),
                                220                 :                :                  errmsg("could not open file \"%s\": %m", path)));
                                221                 :                : 
  116 rhaas@postgresql.org      222                 :GNC          12 :     return file;
                                223                 :                : }
                                224                 :                : 
                                225                 :                : /*
                                226                 :                :  * Remove a WAL summary file if the last modification time precedes the
                                227                 :                :  * cutoff time.
                                228                 :                :  */
                                229                 :                : void
                                230                 :             67 : RemoveWalSummaryIfOlderThan(WalSummaryFile *ws, time_t cutoff_time)
                                231                 :                : {
                                232                 :                :     char        path[MAXPGPATH];
                                233                 :                :     struct stat statbuf;
                                234                 :                : 
                                235                 :             67 :     snprintf(path, MAXPGPATH,
                                236                 :                :              XLOGDIR "/summaries/%08X%08X%08X%08X%08X.summary",
                                237                 :                :              ws->tli,
                                238                 :             67 :              LSN_FORMAT_ARGS(ws->start_lsn),
                                239                 :             67 :              LSN_FORMAT_ARGS(ws->end_lsn));
                                240                 :                : 
                                241         [ -  + ]:             67 :     if (lstat(path, &statbuf) != 0)
                                242                 :                :     {
  116 rhaas@postgresql.org      243         [ #  # ]:UNC           0 :         if (errno == ENOENT)
                                244                 :              0 :             return;
                                245         [ #  # ]:              0 :         ereport(ERROR,
                                246                 :                :                 (errcode_for_file_access(),
                                247                 :                :                  errmsg("could not stat file \"%s\": %m", path)));
                                248                 :                :     }
  116 rhaas@postgresql.org      249         [ +  - ]:GNC          67 :     if (statbuf.st_mtime >= cutoff_time)
                                250                 :             67 :         return;
  116 rhaas@postgresql.org      251         [ #  # ]:UNC           0 :     if (unlink(path) != 0)
                                252         [ #  # ]:              0 :         ereport(ERROR,
                                253                 :                :                 (errcode_for_file_access(),
                                254                 :                :                  errmsg("could not stat file \"%s\": %m", path)));
                                255         [ #  # ]:              0 :     ereport(DEBUG2,
                                256                 :                :             (errmsg_internal("removing file \"%s\"", path)));
                                257                 :                : }
                                258                 :                : 
                                259                 :                : /*
                                260                 :                :  * Test whether a filename looks like a WAL summary file.
                                261                 :                :  */
                                262                 :                : static bool
  116 rhaas@postgresql.org      263                 :GNC         359 : IsWalSummaryFilename(char *filename)
                                264                 :                : {
                                265         [ +  + ]:            606 :     return strspn(filename, "0123456789ABCDEF") == 40 &&
                                266         [ +  - ]:            247 :         strcmp(filename + 40, ".summary") == 0;
                                267                 :                : }
                                268                 :                : 
                                269                 :                : /*
                                270                 :                :  * Data read callback for use with CreateBlockRefTableReader.
                                271                 :                :  */
                                272                 :                : int
                                273                 :             12 : ReadWalSummary(void *wal_summary_io, void *data, int length)
                                274                 :                : {
                                275                 :             12 :     WalSummaryIO *io = wal_summary_io;
                                276                 :                :     int         nbytes;
                                277                 :                : 
                                278                 :             12 :     nbytes = FileRead(io->file, data, length, io->filepos,
                                279                 :                :                       WAIT_EVENT_WAL_SUMMARY_READ);
                                280         [ -  + ]:             12 :     if (nbytes < 0)
  116 rhaas@postgresql.org      281         [ #  # ]:UNC           0 :         ereport(ERROR,
                                282                 :                :                 (errcode_for_file_access(),
                                283                 :                :                  errmsg("could not read file \"%s\": %m",
                                284                 :                :                         FilePathName(io->file))));
                                285                 :                : 
  116 rhaas@postgresql.org      286                 :GNC          12 :     io->filepos += nbytes;
                                287                 :             12 :     return nbytes;
                                288                 :                : }
                                289                 :                : 
                                290                 :                : /*
                                291                 :                :  * Data write callback for use with WriteBlockRefTable.
                                292                 :                :  */
                                293                 :                : int
                                294                 :             69 : WriteWalSummary(void *wal_summary_io, void *data, int length)
                                295                 :                : {
                                296                 :             69 :     WalSummaryIO *io = wal_summary_io;
                                297                 :                :     int         nbytes;
                                298                 :                : 
                                299                 :             69 :     nbytes = FileWrite(io->file, data, length, io->filepos,
                                300                 :                :                        WAIT_EVENT_WAL_SUMMARY_WRITE);
                                301         [ -  + ]:             69 :     if (nbytes < 0)
  116 rhaas@postgresql.org      302         [ #  # ]:UNC           0 :         ereport(ERROR,
                                303                 :                :                 (errcode_for_file_access(),
                                304                 :                :                  errmsg("could not write file \"%s\": %m",
                                305                 :                :                         FilePathName(io->file))));
  116 rhaas@postgresql.org      306         [ -  + ]:GNC          69 :     if (nbytes != length)
  116 rhaas@postgresql.org      307         [ #  # ]:UNC           0 :         ereport(ERROR,
                                308                 :                :                 (errcode_for_file_access(),
                                309                 :                :                  errmsg("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
                                310                 :                :                         FilePathName(io->file), nbytes,
                                311                 :                :                         length, (unsigned) io->filepos),
                                312                 :                :                  errhint("Check free disk space.")));
                                313                 :                : 
  116 rhaas@postgresql.org      314                 :GNC          69 :     io->filepos += nbytes;
                                315                 :             69 :     return nbytes;
                                316                 :                : }
                                317                 :                : 
                                318                 :                : /*
                                319                 :                :  * Error-reporting callback for use with CreateBlockRefTableReader.
                                320                 :                :  */
                                321                 :                : void
  116 rhaas@postgresql.org      322                 :UNC           0 : ReportWalSummaryError(void *callback_arg, char *fmt,...)
                                323                 :                : {
                                324                 :                :     StringInfoData buf;
                                325                 :                :     va_list     ap;
                                326                 :                :     int         needed;
                                327                 :                : 
                                328                 :              0 :     initStringInfo(&buf);
                                329                 :                :     for (;;)
                                330                 :                :     {
                                331                 :              0 :         va_start(ap, fmt);
                                332                 :              0 :         needed = appendStringInfoVA(&buf, fmt, ap);
                                333                 :              0 :         va_end(ap);
                                334         [ #  # ]:              0 :         if (needed == 0)
                                335                 :              0 :             break;
                                336                 :              0 :         enlargeStringInfo(&buf, needed);
                                337                 :                :     }
                                338         [ #  # ]:              0 :     ereport(ERROR,
                                339                 :                :             errcode(ERRCODE_DATA_CORRUPTED),
                                340                 :                :             errmsg_internal("%s", buf.data));
                                341                 :                : }
                                342                 :                : 
                                343                 :                : /*
                                344                 :                :  * Comparator to sort a List of WalSummaryFile objects by start_lsn.
                                345                 :                :  */
                                346                 :                : static int
  116 rhaas@postgresql.org      347                 :GNC           5 : ListComparatorForWalSummaryFiles(const ListCell *a, const ListCell *b)
                                348                 :                : {
                                349                 :              5 :     WalSummaryFile *ws1 = lfirst(a);
                                350                 :              5 :     WalSummaryFile *ws2 = lfirst(b);
                                351                 :                : 
   58 nathan@postgresql.or      352                 :              5 :     return pg_cmp_u64(ws1->start_lsn, ws2->start_lsn);
                                353                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622