LCOV - differential code coverage report
Current view: top level - src/bin/pg_waldump - pg_waldump.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 49.8 % 532 265 18 51 144 54 47 116 47 55 157 157 9 2
Current Date: 2023-04-08 17:13:01 Functions: 68.4 % 19 13 1 5 11 2 6 13
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 58.3 % 12 7 5 7
Legend: Lines: hit not hit (60,120] days: 73.3 % 45 33 12 33
(180,240] days: 75.0 % 4 3 1 2 1
(240..) days: 47.1 % 471 222 51 144 54 47 116 5 54 133 122
Function coverage date bins:
(60,120] days: 100.0 % 2 2 2
(180,240] days: 0.0 % 1 0 1
(240..) days: 31.4 % 35 11 5 11 6 13

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * pg_waldump.c - decode and display WAL
                                  4                 :  *
                                  5                 :  * Copyright (c) 2013-2023, PostgreSQL Global Development Group
                                  6                 :  *
                                  7                 :  * IDENTIFICATION
                                  8                 :  *        src/bin/pg_waldump/pg_waldump.c
                                  9                 :  *-------------------------------------------------------------------------
                                 10                 :  */
                                 11                 : 
                                 12                 : #define FRONTEND 1
                                 13                 : #include "postgres.h"
                                 14                 : 
                                 15                 : #include <dirent.h>
                                 16                 : #include <limits.h>
                                 17                 : #include <signal.h>
                                 18                 : #include <sys/stat.h>
                                 19                 : #include <unistd.h>
                                 20                 : 
                                 21                 : #include "access/transam.h"
                                 22                 : #include "access/xlog_internal.h"
                                 23                 : #include "access/xlogreader.h"
                                 24                 : #include "access/xlogrecord.h"
                                 25                 : #include "access/xlogstats.h"
                                 26                 : #include "common/fe_memutils.h"
                                 27                 : #include "common/file_perm.h"
                                 28                 : #include "common/file_utils.h"
                                 29                 : #include "common/logging.h"
                                 30                 : #include "common/relpath.h"
                                 31                 : #include "getopt_long.h"
                                 32                 : #include "rmgrdesc.h"
                                 33                 : #include "storage/bufpage.h"
                                 34                 : 
                                 35                 : /*
                                 36                 :  * NOTE: For any code change or issue fix here, it is highly recommended to
                                 37                 :  * give a thought about doing the same in pg_walinspect contrib module as well.
                                 38                 :  */
                                 39                 : 
                                 40                 : static const char *progname;
                                 41                 : 
                                 42                 : static int  WalSegSz;
                                 43                 : static volatile sig_atomic_t time_to_stop = false;
                                 44                 : 
                                 45                 : static const RelFileLocator emptyRelFileLocator = {0, 0, 0};
                                 46                 : 
                                 47                 : typedef struct XLogDumpPrivate
                                 48                 : {
                                 49                 :     TimeLineID  timeline;
                                 50                 :     XLogRecPtr  startptr;
                                 51                 :     XLogRecPtr  endptr;
                                 52                 :     bool        endptr_reached;
                                 53                 : } XLogDumpPrivate;
                                 54                 : 
                                 55                 : typedef struct XLogDumpConfig
                                 56                 : {
                                 57                 :     /* display options */
                                 58                 :     bool        quiet;
                                 59                 :     bool        bkp_details;
                                 60                 :     int         stop_after_records;
                                 61                 :     int         already_displayed_records;
                                 62                 :     bool        follow;
                                 63                 :     bool        stats;
                                 64                 :     bool        stats_per_record;
                                 65                 : 
                                 66                 :     /* filter options */
                                 67                 :     bool        filter_by_rmgr[RM_MAX_ID + 1];
                                 68                 :     bool        filter_by_rmgr_enabled;
                                 69                 :     TransactionId filter_by_xid;
                                 70                 :     bool        filter_by_xid_enabled;
                                 71                 :     RelFileLocator filter_by_relation;
                                 72                 :     bool        filter_by_extended;
                                 73                 :     bool        filter_by_relation_enabled;
                                 74                 :     BlockNumber filter_by_relation_block;
                                 75                 :     bool        filter_by_relation_block_enabled;
                                 76                 :     ForkNumber  filter_by_relation_forknum;
                                 77                 :     bool        filter_by_fpw;
                                 78                 : 
                                 79                 :     /* save options */
                                 80                 :     char       *save_fullpage_path;
                                 81                 : } XLogDumpConfig;
                                 82                 : 
                                 83                 : 
                                 84                 : /*
                                 85                 :  * When sigint is called, just tell the system to exit at the next possible
                                 86                 :  * moment.
                                 87                 :  */
                                 88                 : #ifndef WIN32
                                 89                 : 
                                 90                 : static void
  207 tgl                        91 UNC           0 : sigint_handler(SIGNAL_ARGS)
                                 92                 : {
  493 michael                    93 UIC           0 :     time_to_stop = true;
                                 94               0 : }
                                 95                 : #endif
                                 96                 : 
                                 97                 : static void
 3698 alvherre                   98               0 : print_rmgr_list(void)
 3698 alvherre                   99 EUB             : {
                                100                 :     int         i;
                                101                 : 
  368 jdavis                    102 UBC           0 :     for (i = 0; i <= RM_MAX_BUILTIN_ID; i++)
                                103                 :     {
  368 jdavis                    104 UIC           0 :         printf("%s\n", GetRmgrDesc(i)->rm_name);
                                105                 :     }
 3698 alvherre                  106 UBC           0 : }
                                107                 : 
                                108                 : /*
                                109                 :  * Check whether directory exists and whether we can open it. Keep errno set so
 3698 alvherre                  110 EUB             :  * that the caller can report errors somewhat more accurately.
                                111                 :  */
                                112                 : static bool
 3698 alvherre                  113 GIC          45 : verify_directory(const char *directory)
 3698 alvherre                  114 EUB             : {
 3602 bruce                     115 GIC          45 :     DIR        *dir = opendir(directory);
                                116                 : 
 3698 alvherre                  117              45 :     if (dir == NULL)
                                118               1 :         return false;
                                119              44 :     closedir(dir);
                                120              44 :     return true;
 3698 alvherre                  121 ECB             : }
                                122                 : 
                                123                 : /*
                                124                 :  * Create if necessary the directory storing the full-page images extracted
                                125                 :  * from the WAL records read.
                                126                 :  */
                                127                 : static void
  103 michael                   128 GNC           1 : create_fullpage_directory(char *path)
                                129                 : {
                                130                 :     int         ret;
                                131                 : 
                                132               1 :     switch ((ret = pg_check_dir(path)))
                                133                 :     {
                                134               1 :         case 0:
                                135                 :             /* Does not exist, so create it */
                                136               1 :             if (pg_mkdir_p(path, pg_dir_create_mode) < 0)
  103 michael                   137 UNC           0 :                 pg_fatal("could not create directory \"%s\": %m", path);
  103 michael                   138 GNC           1 :             break;
  103 michael                   139 UNC           0 :         case 1:
                                140                 :             /* Present and empty, so do nothing */
                                141               0 :             break;
                                142               0 :         case 2:
                                143                 :         case 3:
                                144                 :         case 4:
                                145                 :             /* Exists and not empty */
                                146               0 :             pg_fatal("directory \"%s\" exists but is not empty", path);
                                147                 :             break;
                                148               0 :         default:
                                149                 :             /* Trouble accessing directory */
                                150               0 :             pg_fatal("could not access directory \"%s\": %m", path);
                                151                 :     }
  103 michael                   152 GNC           1 : }
                                153                 : 
 3698 alvherre                  154 ECB             : /*
                                155                 :  * Split a pathname as dirname(1) and basename(1) would.
                                156                 :  *
                                157                 :  * XXX this probably doesn't do very well on Windows.  We probably need to
                                158                 :  * apply canonicalize_path(), at the very least.
                                159                 :  */
                                160                 : static void
 3698 alvherre                  161 GIC           1 : split_path(const char *path, char **dir, char **fname)
                                162                 : {
                                163                 :     char       *sep;
                                164                 : 
                                165                 :     /* split filepath into directory & filename */
                                166               1 :     sep = strrchr(path, '/');
 3698 alvherre                  167 ECB             : 
                                168                 :     /* directory path */
 3698 alvherre                  169 GIC           1 :     if (sep != NULL)
                                170                 :     {
 1222 alvherre                  171 CBC           1 :         *dir = pnstrdup(path, sep - path);
 3698 alvherre                  172 GIC           1 :         *fname = pg_strdup(sep + 1);
 3698 alvherre                  173 ECB             :     }
                                174                 :     /* local directory */
                                175                 :     else
 3698 alvherre                  176 EUB             :     {
 3698 alvherre                  177 LBC           0 :         *dir = NULL;
 3698 alvherre                  178 UBC           0 :         *fname = pg_strdup(path);
                                179                 :     }
 3698 alvherre                  180 GBC           1 : }
 3698 alvherre                  181 EUB             : 
                                182                 : /*
                                183                 :  * Open the file in the valid target directory.
                                184                 :  *
                                185                 :  * return a read only fd
                                186                 :  */
                                187                 : static int
 2028 andres                    188 GIC          88 : open_file_in_directory(const char *directory, const char *fname)
 3698 alvherre                  189 EUB             : {
 3698 alvherre                  190 GIC          88 :     int         fd = -1;
 3698 alvherre                  191 ECB             :     char        fpath[MAXPGPATH];
                                192                 : 
 2028 andres                    193 GIC          88 :     Assert(directory != NULL);
                                194                 : 
                                195              88 :     snprintf(fpath, MAXPGPATH, "%s/%s", directory, fname);
                                196              88 :     fd = open(fpath, O_RDONLY | PG_BINARY, 0);
                                197                 : 
                                198              88 :     if (fd < 0 && errno != ENOENT)
  366 tgl                       199 UIC           0 :         pg_fatal("could not open file \"%s\": %m", fname);
 2028 andres                    200 CBC          88 :     return fd;
                                201                 : }
                                202                 : 
                                203                 : /*
                                204                 :  * Try to find fname in the given directory. Returns true if it is found,
 2028 andres                    205 ECB             :  * false otherwise. If fname is NULL, search the complete directory for any
                                206                 :  * file with a valid WAL file name. If file is successfully opened, set the
                                207                 :  * wal segment size.
                                208                 :  */
                                209                 : static bool
 1986 peter_e                   210 CBC          44 : search_directory(const char *directory, const char *fname)
 2028 andres                    211 ECB             : {
 2028 andres                    212 GIC          44 :     int         fd = -1;
                                213                 :     DIR        *xldir;
                                214                 : 
                                215                 :     /* open file if valid filename is provided */
 2028 andres                    216 GBC          44 :     if (fname != NULL)
                                217               1 :         fd = open_file_in_directory(directory, fname);
                                218                 : 
 2028 andres                    219 ECB             :     /*
                                220                 :      * A valid file name is not passed, so search the complete directory.  If
                                221                 :      * we find any file whose name is a valid WAL file name then try to open
                                222                 :      * it.  If we cannot open it, bail out.
                                223                 :      */
 2028 andres                    224 GIC          43 :     else if ((xldir = opendir(directory)) != NULL)
                                225                 :     {
                                226                 :         struct dirent *xlde;
 2028 andres                    227 ECB             : 
 2028 andres                    228 GIC          96 :         while ((xlde = readdir(xldir)) != NULL)
 2028 andres                    229 ECB             :         {
 2028 andres                    230 GIC          96 :             if (IsXLogFileName(xlde->d_name))
                                231                 :             {
 2028 andres                    232 CBC          43 :                 fd = open_file_in_directory(directory, xlde->d_name);
  382 andres                    233 GIC          43 :                 fname = pg_strdup(xlde->d_name);
 2028 andres                    234 CBC          43 :                 break;
 2028 andres                    235 ECB             :             }
                                236                 :         }
                                237                 : 
 2028 andres                    238 GBC          43 :         closedir(xldir);
 2028 andres                    239 ECB             :     }
                                240                 : 
                                241                 :     /* set WalSegSz if file is successfully opened */
 2028 andres                    242 GIC          44 :     if (fd >= 0)
                                243                 :     {
                                244                 :         PGAlignedXLogBlock buf;
                                245                 :         int         r;
                                246                 : 
 1681 tgl                       247              44 :         r = read(fd, buf.data, XLOG_BLCKSZ);
 1726 michael                   248              44 :         if (r == XLOG_BLCKSZ)
 2028 andres                    249 ECB             :         {
 1681 tgl                       250 GIC          44 :             XLogLongPageHeader longhdr = (XLogLongPageHeader) buf.data;
 2028 andres                    251 ECB             : 
 2028 andres                    252 GIC          44 :             WalSegSz = longhdr->xlp_seg_size;
                                253                 : 
                                254              44 :             if (!IsValidWalSegSize(WalSegSz))
  366 tgl                       255 CBC           1 :                 pg_fatal(ngettext("WAL segment size must be a power of two between 1 MB and 1 GB, but the WAL file \"%s\" header specifies %d byte",
  366 tgl                       256 ECB             :                                   "WAL segment size must be a power of two between 1 MB and 1 GB, but the WAL file \"%s\" header specifies %d bytes",
                                257                 :                                   WalSegSz),
                                258                 :                          fname, WalSegSz);
                                259                 :         }
  408 andres                    260 UIC           0 :         else if (r < 0)
  366 tgl                       261               0 :             pg_fatal("could not read file \"%s\": %m",
                                262                 :                      fname);
 2028 andres                    263 ECB             :         else
  366 tgl                       264 UIC           0 :             pg_fatal("could not read file \"%s\": read %d of %d",
                                265                 :                      fname, r, XLOG_BLCKSZ);
 2028 andres                    266 GIC          43 :         close(fd);
 2028 andres                    267 CBC          43 :         return true;
                                268                 :     }
 2028 andres                    269 ECB             : 
 2028 andres                    270 UIC           0 :     return false;
 2028 andres                    271 ECB             : }
                                272                 : 
                                273                 : /*
                                274                 :  * Identify the target directory.
                                275                 :  *
                                276                 :  * Try to find the file in several places:
                                277                 :  * if directory != NULL:
                                278                 :  *   directory /
                                279                 :  *   directory / XLOGDIR /
                                280                 :  * else
                                281                 :  *   .
                                282                 :  *   XLOGDIR /
                                283                 :  *   $PGDATA / XLOGDIR /
                                284                 :  *
                                285                 :  * The valid target directory is returned.
                                286                 :  */
 1293 alvherre                  287                 : static char *
 1293 alvherre                  288 GIC          44 : identify_target_directory(char *directory, char *fname)
 2028 andres                    289 ECB             : {
                                290                 :     char        fpath[MAXPGPATH];
                                291                 : 
 2028 andres                    292 GIC          44 :     if (directory != NULL)
 2028 andres                    293 ECB             :     {
 2028 andres                    294 CBC          44 :         if (search_directory(directory, fname))
 1293 alvherre                  295 GIC          43 :             return pg_strdup(directory);
                                296                 : 
                                297                 :         /* directory / XLOGDIR */
 2028 andres                    298 UIC           0 :         snprintf(fpath, MAXPGPATH, "%s/%s", directory, XLOGDIR);
 2028 andres                    299 UBC           0 :         if (search_directory(fpath, fname))
 1293 alvherre                  300               0 :             return pg_strdup(fpath);
                                301                 :     }
                                302                 :     else
 3698 alvherre                  303 EUB             :     {
                                304                 :         const char *datadir;
 3698 alvherre                  305 ECB             : 
 2028 andres                    306                 :         /* current directory */
 2028 andres                    307 UIC           0 :         if (search_directory(".", fname))
 1293 alvherre                  308               0 :             return pg_strdup(".");
 2028 andres                    309 EUB             :         /* XLOGDIR */
 2028 andres                    310 UIC           0 :         if (search_directory(XLOGDIR, fname))
 1293 alvherre                  311               0 :             return pg_strdup(XLOGDIR);
                                312                 : 
 3698                           313               0 :         datadir = getenv("PGDATA");
                                314                 :         /* $PGDATA / XLOGDIR */
                                315               0 :         if (datadir != NULL)
                                316                 :         {
 2028 andres                    317               0 :             snprintf(fpath, MAXPGPATH, "%s/%s", datadir, XLOGDIR);
                                318               0 :             if (search_directory(fpath, fname))
 1293 alvherre                  319               0 :                 return pg_strdup(fpath);
                                320                 :         }
                                321                 :     }
                                322                 : 
                                323                 :     /* could not locate WAL file */
 2028 andres                    324               0 :     if (fname)
  366 tgl                       325               0 :         pg_fatal("could not locate WAL file \"%s\"", fname);
                                326                 :     else
  366 tgl                       327 LBC           0 :         pg_fatal("could not find any WAL file");
                                328                 : 
                                329                 :     return NULL;                /* not reached */
                                330                 : }
 3698 alvherre                  331 ECB             : 
                                332                 : /* pg_waldump's XLogReaderRoutine->segment_open callback */
 1061                           333                 : static void
 1061 alvherre                  334 CBC          43 : WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo,
                                335                 :                    TimeLineID *tli_p)
                                336                 : {
 1231 alvherre                  337 GBC          43 :     TimeLineID  tli = *tli_p;
 1231 alvherre                  338 EUB             :     char        fname[MAXPGPATH];
                                339                 :     int         tries;
                                340                 : 
 1061 alvherre                  341 GIC          43 :     XLogFileName(fname, tli, nextSegNo, state->segcxt.ws_segsize);
                                342                 : 
                                343                 :     /*
                                344                 :      * In follow mode there is a short period of time after the server has
                                345                 :      * written the end of the previous file before the new file is available.
 1231 alvherre                  346 EUB             :      * So we loop for 5 seconds looking for the file to appear before giving
                                347                 :      * up.
                                348                 :      */
 1231 alvherre                  349 GBC          43 :     for (tries = 0; tries < 10; tries++)
 3698 alvherre                  350 EUB             :     {
 1061 alvherre                  351 GIC          43 :         state->seg.ws_file = open_file_in_directory(state->segcxt.ws_dir, fname);
 1061 alvherre                  352 GBC          43 :         if (state->seg.ws_file >= 0)
 1061 alvherre                  353 GIC          43 :             return;
 1231 alvherre                  354 UBC           0 :         if (errno == ENOENT)
 3698 alvherre                  355 UIC           0 :         {
 1726 michael                   356 UBC           0 :             int         save_errno = errno;
 3698 alvherre                  357 EUB             : 
 1231                           358                 :             /* File not there yet, try again */
 1231 alvherre                  359 UIC           0 :             pg_usleep(500 * 1000);
                                360                 : 
                                361               0 :             errno = save_errno;
                                362               0 :             continue;
 3698 alvherre                  363 EUB             :         }
 1231                           364                 :         /* Any other error, fall through and fail */
 1231 alvherre                  365 UIC           0 :         break;
 3698 alvherre                  366 EUB             :     }
                                367                 : 
  366 tgl                       368 UIC           0 :     pg_fatal("could not find file \"%s\": %m", fname);
                                369                 : }
                                370                 : 
                                371                 : /*
                                372                 :  * pg_waldump's XLogReaderRoutine->segment_close callback.  Same as
 1066 alvherre                  373 ECB             :  * wal_segment_close
                                374                 :  */
                                375                 : static void
 1066 alvherre                  376 CBC          43 : WALDumpCloseSegment(XLogReaderState *state)
                                377                 : {
 1066 alvherre                  378 GIC          43 :     close(state->seg.ws_file);
                                379                 :     /* need to check errno? */
 1066 alvherre                  380 CBC          43 :     state->seg.ws_file = -1;
 1066 alvherre                  381 GIC          43 : }
                                382                 : 
                                383                 : /* pg_waldump's XLogReaderRoutine->page_read callback */
                                384                 : static int
  699 tmunro                    385             762 : WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
                                386                 :                 XLogRecPtr targetPtr, char *readBuff)
                                387                 : {
  699 tmunro                    388 CBC         762 :     XLogDumpPrivate *private = state->private_data;
 3698 alvherre                  389 GIC         762 :     int         count = XLOG_BLCKSZ;
 1231 alvherre                  390 ECB             :     WALReadError errinfo;
 3698                           391                 : 
  699 tmunro                    392 CBC         762 :     if (private->endptr != InvalidXLogRecPtr)
 3698 alvherre                  393 EUB             :     {
  699 tmunro                    394 GBC         762 :         if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
 3698 alvherre                  395             677 :             count = XLOG_BLCKSZ;
  699 tmunro                    396 GIC          85 :         else if (targetPagePtr + reqLen <= private->endptr)
                                397              42 :             count = private->endptr - targetPagePtr;
 3698 alvherre                  398 EUB             :         else
                                399                 :         {
  699 tmunro                    400 GBC          43 :             private->endptr_reached = true;
                                401              43 :             return -1;
                                402                 :         }
                                403                 :     }
 3698 alvherre                  404 EUB             : 
  699 tmunro                    405 GIC         719 :     if (!WALRead(state, readBuff, targetPagePtr, count, private->timeline,
                                406                 :                  &errinfo))
 1231 alvherre                  407 EUB             :     {
 1231 alvherre                  408 UIC           0 :         WALOpenSegment *seg = &errinfo.wre_seg;
                                409                 :         char        fname[MAXPGPATH];
                                410                 : 
                                411               0 :         XLogFileName(fname, seg->ws_tli, seg->ws_segno,
                                412                 :                      state->segcxt.ws_segsize);
                                413                 : 
                                414               0 :         if (errinfo.wre_errno != 0)
 1231 alvherre                  415 ECB             :         {
 1231 alvherre                  416 UIC           0 :             errno = errinfo.wre_errno;
  366 tgl                       417 LBC           0 :             pg_fatal("could not read from file %s, offset %d: %m",
                                418                 :                      fname, errinfo.wre_off);
 1231 alvherre                  419 ECB             :         }
                                420                 :         else
  366 tgl                       421 UIC           0 :             pg_fatal("could not read from file %s, offset %d: read %d of %d",
                                422                 :                      fname, errinfo.wre_off, errinfo.wre_read,
                                423                 :                      errinfo.wre_req);
 1231 alvherre                  424 ECB             :     }
                                425                 : 
  699 tmunro                    426 GIC         719 :     return count;
 3698 alvherre                  427 ECB             : }
                                428                 : 
                                429                 : /*
                                430                 :  * Boolean to return whether the given WAL record matches a specific relation
  381 tmunro                    431                 :  * and optionally block.
                                432                 :  */
                                433                 : static bool
  381 tmunro                    434 CBC       25740 : XLogRecordMatchesRelationBlock(XLogReaderState *record,
                                435                 :                                RelFileLocator matchRlocator,
  381 tmunro                    436 ECB             :                                BlockNumber matchBlock,
                                437                 :                                ForkNumber matchFork)
                                438                 : {
                                439                 :     int         block_id;
                                440                 : 
  381 tmunro                    441 GIC       50976 :     for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
                                442                 :     {
                                443                 :         RelFileLocator rlocator;
  381 tmunro                    444 ECB             :         ForkNumber  forknum;
                                445                 :         BlockNumber blk;
                                446                 : 
  363 tgl                       447 GBC       25436 :         if (!XLogRecGetBlockTagExtended(record, block_id,
                                448                 :                                         &rlocator, &forknum, &blk, NULL))
  381 tmunro                    449 GIC          20 :             continue;
  381 tmunro                    450 EUB             : 
  381 tmunro                    451 GIC       25416 :         if ((matchFork == InvalidForkNumber || matchFork == forknum) &&
  277 rhaas                     452 GNC       25416 :             (RelFileLocatorEquals(matchRlocator, emptyRelFileLocator) ||
                                453           25416 :              RelFileLocatorEquals(matchRlocator, rlocator)) &&
  381 tmunro                    454 UIC           0 :             (matchBlock == InvalidBlockNumber || matchBlock == blk))
  381 tmunro                    455 GBC         200 :             return true;
  381 tmunro                    456 EUB             :     }
                                457                 : 
  381 tmunro                    458 GIC       25540 :     return false;
                                459                 : }
  381 tmunro                    460 EUB             : 
                                461                 : /*
                                462                 :  * Boolean to return whether the given WAL record contains a full page write.
                                463                 :  */
                                464                 : static bool
  381 tmunro                    465 LBC           0 : XLogRecordHasFPW(XLogReaderState *record)
                                466                 : {
                                467                 :     int         block_id;
                                468                 : 
  381 tmunro                    469 UIC           0 :     for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
                                470                 :     {
                                471               0 :         if (!XLogRecHasBlockRef(record, block_id))
                                472               0 :             continue;
  381 tmunro                    473 ECB             : 
  381 tmunro                    474 UIC           0 :         if (XLogRecHasBlockImage(record, block_id))
                                475               0 :             return true;
                                476                 :     }
                                477                 : 
                                478               0 :     return false;
                                479                 : }
  381 tmunro                    480 ECB             : 
                                481                 : /*
                                482                 :  * Function to externally save all FPWs stored in the given WAL record.
                                483                 :  * Decompression is applied to all the blocks saved, if necessary.
                                484                 :  */
                                485                 : static void
  103 michael                   486 GNC         200 : XLogRecordSaveFPWs(XLogReaderState *record, const char *savepath)
                                487                 : {
                                488                 :     int         block_id;
                                489                 : 
                                490             400 :     for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
                                491                 :     {
                                492                 :         PGAlignedBlock buf;
                                493                 :         Page        page;
                                494                 :         char        filename[MAXPGPATH];
                                495                 :         char        forkname[FORKNAMECHARS + 2];    /* _ + terminating zero */
                                496                 :         FILE       *file;
                                497                 :         BlockNumber blk;
                                498                 :         RelFileLocator rnode;
                                499                 :         ForkNumber  fork;
                                500                 : 
                                501             200 :         if (!XLogRecHasBlockRef(record, block_id))
                                502             199 :             continue;
                                503                 : 
                                504             200 :         if (!XLogRecHasBlockImage(record, block_id))
                                505             199 :             continue;
                                506                 : 
                                507               1 :         page = (Page) buf.data;
                                508                 : 
                                509                 :         /* Full page exists, so let's save it */
                                510               1 :         if (!RestoreBlockImage(record, block_id, page))
  103 michael                   511 UNC           0 :             pg_fatal("%s", record->errormsg_buf);
                                512                 : 
  103 michael                   513 GNC           1 :         (void) XLogRecGetBlockTagExtended(record, block_id,
                                514                 :                                           &rnode, &fork, &blk, NULL);
                                515                 : 
                                516               1 :         if (fork >= 0 && fork <= MAX_FORKNUM)
                                517               1 :             sprintf(forkname, "_%s", forkNames[fork]);
                                518                 :         else
  103 michael                   519 UNC           0 :             pg_fatal("invalid fork number: %u", fork);
                                520                 : 
  103 michael                   521 GNC           1 :         snprintf(filename, MAXPGPATH, "%s/%08X-%08X.%u.%u.%u.%u%s", savepath,
                                522               1 :                  LSN_FORMAT_ARGS(record->ReadRecPtr),
                                523                 :                  rnode.spcOid, rnode.dbOid, rnode.relNumber, blk, forkname);
                                524                 : 
                                525               1 :         file = fopen(filename, PG_BINARY_W);
                                526               1 :         if (!file)
  103 michael                   527 UNC           0 :             pg_fatal("could not open file \"%s\": %m", filename);
                                528                 : 
  103 michael                   529 GNC           1 :         if (fwrite(page, BLCKSZ, 1, file) != 1)
  103 michael                   530 UNC           0 :             pg_fatal("could not write file \"%s\": %m", filename);
                                531                 : 
  103 michael                   532 GNC           1 :         if (fclose(file) != 0)
  103 michael                   533 UNC           0 :             pg_fatal("could not close file \"%s\": %m", filename);
                                534                 :     }
  103 michael                   535 GNC         200 : }
                                536                 : 
                                537                 : /*
                                538                 :  * Print a record to stdout
                                539                 :  */
                                540                 : static void
 3062 heikki.linnakangas        541 UIC           0 : XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record)
 3124 andres                    542 ECB             : {
                                543                 :     const char *id;
  368 jdavis                    544 LBC           0 :     const RmgrDescData *desc = GetRmgrDesc(XLogRecGetRmid(record));
                                545                 :     uint32      rec_len;
 2134 andres                    546 ECB             :     uint32      fpi_len;
 3062 heikki.linnakangas        547 LBC           0 :     uint8       info = XLogRecGetInfo(record);
                                548               0 :     XLogRecPtr  xl_prev = XLogRecGetPrev(record);
 1251 andres                    549 EUB             :     StringInfoData s;
 3062 heikki.linnakangas        550 ECB             : 
  366 jdavis                    551 UIC           0 :     XLogRecGetLen(record, &rec_len, &fpi_len);
                                552                 : 
 3062 heikki.linnakangas        553 LBC           0 :     printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
                                554                 :            desc->rm_name,
                                555                 :            rec_len, XLogRecGetTotalLen(record),
                                556                 :            XLogRecGetXid(record),
                                557                 :            LSN_FORMAT_ARGS(record->ReadRecPtr),
                                558                 :            LSN_FORMAT_ARGS(xl_prev));
                                559                 : 
 1258 andres                    560 UBC           0 :     id = desc->rm_identify(info);
 1258 andres                    561 UIC           0 :     if (id == NULL)
                                562               0 :         printf("desc: UNKNOWN (%x) ", info & ~XLR_INFO_MASK);
                                563                 :     else
 1258 andres                    564 UBC           0 :         printf("desc: %s ", id);
                                565                 : 
 1251                           566               0 :     initStringInfo(&s);
                                567               0 :     desc->rm_desc(&s, record);
 1251 andres                    568 UIC           0 :     printf("%s", s.data);
  649 michael                   569 EUB             : 
  366 jdavis                    570 UBC           0 :     resetStringInfo(&s);
  366 jdavis                    571 UIC           0 :     XLogRecGetBlockRefInfo(record, true, config->bkp_details, &s, NULL);
                                572               0 :     printf("%s", s.data);
  366 jdavis                    573 UBC           0 :     pfree(s.data);
 3698 alvherre                  574 UIC           0 : }
                                575                 : 
                                576                 : /*
                                577                 :  * Display a single row of record counts and sizes for an rmgr or record.
                                578                 :  */
                                579                 : static void
 3124 andres                    580               0 : XLogDumpStatsRow(const char *name,
 2905 andres                    581 ECB             :                  uint64 n, uint64 total_count,
                                582                 :                  uint64 rec_len, uint64 total_rec_len,
                                583                 :                  uint64 fpi_len, uint64 total_fpi_len,
                                584                 :                  uint64 tot_len, uint64 total_len)
 3124                           585                 : {
                                586                 :     double      n_pct,
                                587                 :                 rec_len_pct,
                                588                 :                 fpi_len_pct,
                                589                 :                 tot_len_pct;
                                590                 : 
 2905 andres                    591 UIC           0 :     n_pct = 0;
                                592               0 :     if (total_count != 0)
                                593               0 :         n_pct = 100 * (double) n / total_count;
                                594                 : 
                                595               0 :     rec_len_pct = 0;
 2905 andres                    596 LBC           0 :     if (total_rec_len != 0)
                                597               0 :         rec_len_pct = 100 * (double) rec_len / total_rec_len;
                                598                 : 
                                599               0 :     fpi_len_pct = 0;
                                600               0 :     if (total_fpi_len != 0)
 2905 andres                    601 UIC           0 :         fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
 2905 andres                    602 ECB             : 
 2905 andres                    603 UIC           0 :     tot_len_pct = 0;
                                604               0 :     if (total_len != 0)
 2905 andres                    605 LBC           0 :         tot_len_pct = 100 * (double) tot_len / total_len;
 2905 andres                    606 EUB             : 
 3124 andres                    607 UIC           0 :     printf("%-27s "
 3124 andres                    608 ECB             :            "%20" INT64_MODIFIER "u (%6.02f) "
                                609                 :            "%20" INT64_MODIFIER "u (%6.02f) "
                                610                 :            "%20" INT64_MODIFIER "u (%6.02f) "
                                611                 :            "%20" INT64_MODIFIER "u (%6.02f)\n",
                                612                 :            name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
                                613                 :            tot_len, tot_len_pct);
 3124 andres                    614 UBC           0 : }
                                615                 : 
 3124 andres                    616 ECB             : 
                                617                 : /*
                                618                 :  * Display summary statistics about the records seen so far.
                                619                 :  */
                                620                 : static void
  366 jdavis                    621 LBC           0 : XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
 3124 andres                    622 EUB             : {
                                623                 :     int         ri,
 2878 bruce                     624 ECB             :                 rj;
 3124 andres                    625 UBC           0 :     uint64      total_count = 0;
 3124 andres                    626 UIC           0 :     uint64      total_rec_len = 0;
 3124 andres                    627 LBC           0 :     uint64      total_fpi_len = 0;
 3124 andres                    628 UBC           0 :     uint64      total_len = 0;
                                629                 :     double      rec_len_pct,
 2878 bruce                     630 ECB             :                 fpi_len_pct;
                                631                 : 
                                632                 :     /*
                                633                 :      * Leave if no stats have been computed yet, as tracked by the end LSN.
                                634                 :      */
  493 michael                   635 UIC           0 :     if (XLogRecPtrIsInvalid(stats->endptr))
  493 michael                   636 UBC           0 :         return;
                                637                 : 
                                638                 :     /*
  967 noah                      639 EUB             :      * Each row shows its percentages of the total, so make a first pass to
                                640                 :      * calculate column totals.
                                641                 :      */
 3124 andres                    642                 : 
  367 jdavis                    643 UBC           0 :     for (ri = 0; ri <= RM_MAX_ID; ri++)
                                644                 :     {
  366 jdavis                    645 UIC           0 :         if (!RmgrIdIsValid(ri))
  366 jdavis                    646 UBC           0 :             continue;
                                647                 : 
 3124 andres                    648               0 :         total_count += stats->rmgr_stats[ri].count;
 3124 andres                    649 UIC           0 :         total_rec_len += stats->rmgr_stats[ri].rec_len;
                                650               0 :         total_fpi_len += stats->rmgr_stats[ri].fpi_len;
                                651                 :     }
 2878 bruce                     652               0 :     total_len = total_rec_len + total_fpi_len;
                                653                 : 
  493 michael                   654               0 :     printf("WAL statistics between %X/%X and %X/%X:\n",
  493 michael                   655 EUB             :            LSN_FORMAT_ARGS(stats->startptr), LSN_FORMAT_ARGS(stats->endptr));
                                656                 : 
 3124 andres                    657                 :     /*
                                658                 :      * 27 is strlen("Transaction/COMMIT_PREPARED"), 20 is strlen(2^64), 8 is
 2878 bruce                     659                 :      * strlen("(100.00%)")
                                660                 :      */
 3124 andres                    661                 : 
 3124 andres                    662 UBC           0 :     printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
 3124 andres                    663 EUB             :            "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
                                664                 :            "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
                                665                 :            "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
                                666                 : 
  368 jdavis                    667 UBC           0 :     for (ri = 0; ri <= RM_MAX_ID; ri++)
 3124 andres                    668 EUB             :     {
 2878 bruce                     669                 :         uint64      count,
                                670                 :                     rec_len,
                                671                 :                     fpi_len,
                                672                 :                     tot_len;
                                673                 :         const RmgrDescData *desc;
                                674                 : 
  367 jdavis                    675 UBC           0 :         if (!RmgrIdIsValid(ri))
  368 jdavis                    676 UIC           0 :             continue;
                                677                 : 
                                678               0 :         desc = GetRmgrDesc(ri);
                                679                 : 
 3124 andres                    680               0 :         if (!config->stats_per_record)
                                681                 :         {
                                682               0 :             count = stats->rmgr_stats[ri].count;
                                683               0 :             rec_len = stats->rmgr_stats[ri].rec_len;
                                684               0 :             fpi_len = stats->rmgr_stats[ri].fpi_len;
                                685               0 :             tot_len = rec_len + fpi_len;
 3124 andres                    686 EUB             : 
  367 jdavis                    687 UBC           0 :             if (RmgrIdIsCustom(ri) && count == 0)
  368                           688               0 :                 continue;
                                689                 : 
 3124 andres                    690               0 :             XLogDumpStatsRow(desc->rm_name,
 2905 andres                    691 EUB             :                              count, total_count, rec_len, total_rec_len,
                                692                 :                              fpi_len, total_fpi_len, tot_len, total_len);
                                693                 :         }
 3124                           694                 :         else
                                695                 :         {
 3124 andres                    696 UBC           0 :             for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
                                697                 :             {
 3124 andres                    698 EUB             :                 const char *id;
                                699                 : 
 3124 andres                    700 UBC           0 :                 count = stats->record_stats[ri][rj].count;
 3124 andres                    701 UIC           0 :                 rec_len = stats->record_stats[ri][rj].rec_len;
 3124 andres                    702 UBC           0 :                 fpi_len = stats->record_stats[ri][rj].fpi_len;
 3124 andres                    703 UIC           0 :                 tot_len = rec_len + fpi_len;
                                704                 : 
                                705                 :                 /* Skip undefined combinations and ones that didn't occur */
                                706               0 :                 if (count == 0)
                                707               0 :                     continue;
                                708                 : 
 3124 andres                    709 EUB             :                 /* the upper four bits in xl_info are the rmgr's */
 3124 andres                    710 UIC           0 :                 id = desc->rm_identify(rj << 4);
                                711               0 :                 if (id == NULL)
                                712               0 :                     id = psprintf("UNKNOWN (%x)", rj << 4);
                                713                 : 
                                714               0 :                 XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
                                715                 :                                  count, total_count, rec_len, total_rec_len,
 2905 andres                    716 EUB             :                                  fpi_len, total_fpi_len, tot_len, total_len);
                                717                 :             }
                                718                 :         }
                                719                 :     }
 3124                           720                 : 
 3124 andres                    721 UBC           0 :     printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
 3124 andres                    722 EUB             :            "", "--------", "", "--------", "", "--------", "", "--------");
                                723                 : 
                                724                 :     /*
                                725                 :      * The percentages in earlier rows were calculated against the column
                                726                 :      * total, but the ones that follow are against the row total. Note that
                                727                 :      * these are displayed with a % symbol to differentiate them from the
                                728                 :      * earlier ones, and are thus up to 9 characters long.
                                729                 :      */
                                730                 : 
 2905 andres                    731 UBC           0 :     rec_len_pct = 0;
 2905 andres                    732 UIC           0 :     if (total_len != 0)
                                733               0 :         rec_len_pct = 100 * (double) total_rec_len / total_len;
                                734                 : 
                                735               0 :     fpi_len_pct = 0;
                                736               0 :     if (total_len != 0)
                                737               0 :         fpi_len_pct = 100 * (double) total_fpi_len / total_len;
 2905 andres                    738 EUB             : 
 3124 andres                    739 UIC           0 :     printf("%-27s "
 3124 andres                    740 EUB             :            "%20" INT64_MODIFIER "u %-9s"
                                741                 :            "%20" INT64_MODIFIER "u %-9s"
                                742                 :            "%20" INT64_MODIFIER "u %-9s"
                                743                 :            "%20" INT64_MODIFIER "u %-6s\n",
                                744                 :            "Total", stats->count, "",
 2905                           745                 :            total_rec_len, psprintf("[%.02f%%]", rec_len_pct),
                                746                 :            total_fpi_len, psprintf("[%.02f%%]", fpi_len_pct),
 3124                           747                 :            total_len, "[100%]");
                                748                 : }
                                749                 : 
                                750                 : static void
 3698 alvherre                  751 GIC           1 : usage(void)
                                752                 : {
 2158 peter_e                   753               1 :     printf(_("%s decodes and displays PostgreSQL write-ahead logs for debugging.\n\n"),
                                754                 :            progname);
 2367                           755               1 :     printf(_("Usage:\n"));
 2187                           756               1 :     printf(_("  %s [OPTION]... [STARTSEG [ENDSEG]]\n"), progname);
 2367 peter_e                   757 GBC           1 :     printf(_("\nOptions:\n"));
 2367 peter_e                   758 GIC           1 :     printf(_("  -b, --bkp-details      output detailed information about backup blocks\n"));
  380 tmunro                    759               1 :     printf(_("  -B, --block=N          with --relation, only show records that modify block N\n"));
 2158 peter_e                   760               1 :     printf(_("  -e, --end=RECPTR       stop reading at WAL location RECPTR\n"));
 2367                           761               1 :     printf(_("  -f, --follow           keep retrying after reaching end of WAL\n"));
  380 tmunro                    762 GBC           1 :     printf(_("  -F, --fork=FORK        only show records that modify blocks in fork FORK;\n"
                                763                 :              "                         valid names are main, fsm, vm, init\n"));
 2367 peter_e                   764 GIC           1 :     printf(_("  -n, --limit=N          number of records to display\n"));
  207 tgl                       765 GNC           1 :     printf(_("  -p, --path=PATH        directory in which to find WAL segment files or a\n"
                                766                 :              "                         directory with a ./pg_wal that contains such files\n"
                                767                 :              "                         (default: current directory, ./pg_wal, $PGDATA/pg_wal)\n"));
 1102 rhaas                     768 GIC           1 :     printf(_("  -q, --quiet            do not print any output, except for errors\n"));
 2053 peter_e                   769               1 :     printf(_("  -r, --rmgr=RMGR        only show records generated by resource manager RMGR;\n"
 2153 tgl                       770 EUB             :              "                         use --rmgr=list to list valid resource manager names\n"));
  380 tmunro                    771 GBC           1 :     printf(_("  -R, --relation=T/D/R   only show records that modify blocks in relation T/D/R\n"));
 2158 peter_e                   772 GIC           1 :     printf(_("  -s, --start=RECPTR     start reading at WAL location RECPTR\n"));
  207 tgl                       773 GNC           1 :     printf(_("  -t, --timeline=TLI     timeline from which to read WAL records\n"
                                774                 :              "                         (default: 1 or the value used in STARTSEG)\n"));
 2367 peter_e                   775 GBC           1 :     printf(_("  -V, --version          output version information, then exit\n"));
  381 tmunro                    776 GIC           1 :     printf(_("  -w, --fullpage         only show records with a full page write\n"));
  103 michael                   777 GNC           1 :     printf(_("      --save-fullpage=PATH\n"
                                778                 :              "                         save full page images\n"));
  380 tmunro                    779 GBC           1 :     printf(_("  -x, --xid=XID          only show records with transaction ID XID\n"));
 2153 tgl                       780               1 :     printf(_("  -z, --stats[=record]   show statistics instead of records\n"
 2118 tgl                       781 EUB             :              "                         (optionally, show per-record statistics)\n"));
 2367 peter_e                   782 GBC           1 :     printf(_("  -?, --help             show this help, then exit\n"));
 1136 peter                     783 GIC           1 :     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
 1136 peter                     784 GBC           1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
 3698 alvherre                  785               1 : }
                                786                 : 
 3698 alvherre                  787 EUB             : int
 3698 alvherre                  788 GIC         126 : main(int argc, char **argv)
                                789                 : {
                                790                 :     uint32      xlogid;
                                791                 :     uint32      xrecoff;
                                792                 :     XLogReaderState *xlogreader_state;
  699 tmunro                    793 EUB             :     XLogDumpPrivate private;
                                794                 :     XLogDumpConfig config;
                                795                 :     XLogStats   stats;
                                796                 :     XLogRecord *record;
 3698 alvherre                  797                 :     XLogRecPtr  first_record;
 1293 alvherre                  798 GBC         126 :     char       *waldir = NULL;
 3698 alvherre                  799 EUB             :     char       *errormsg;
                                800                 : 
                                801                 :     static struct option long_options[] = {
                                802                 :         {"bkp-details", no_argument, NULL, 'b'},
  380 tmunro                    803                 :         {"block", required_argument, NULL, 'B'},
 3698 alvherre                  804                 :         {"end", required_argument, NULL, 'e'},
                                805                 :         {"follow", no_argument, NULL, 'f'},
                                806                 :         {"fork", required_argument, NULL, 'F'},
  381 tmunro                    807                 :         {"fullpage", no_argument, NULL, 'w'},
 3698 alvherre                  808                 :         {"help", no_argument, NULL, '?'},
                                809                 :         {"limit", required_argument, NULL, 'n'},
                                810                 :         {"path", required_argument, NULL, 'p'},
 1102 rhaas                     811                 :         {"quiet", no_argument, NULL, 'q'},
                                812                 :         {"relation", required_argument, NULL, 'R'},
                                813                 :         {"rmgr", required_argument, NULL, 'r'},
                                814                 :         {"start", required_argument, NULL, 's'},
                                815                 :         {"timeline", required_argument, NULL, 't'},
                                816                 :         {"xid", required_argument, NULL, 'x'},
                                817                 :         {"version", no_argument, NULL, 'V'},
 3124 andres                    818                 :         {"stats", optional_argument, NULL, 'z'},
                                819                 :         {"save-fullpage", required_argument, NULL, 1},
                                820                 :         {NULL, 0, NULL, 0}
                                821                 :     };
                                822                 : 
                                823                 :     int         option;
 3698 alvherre                  824 GIC         126 :     int         optindex = 0;
                                825                 : 
                                826                 : #ifndef WIN32
  493 michael                   827             126 :     pqsignal(SIGINT, sigint_handler);
                                828                 : #endif
  493 michael                   829 EUB             : 
 1469 peter                     830 GBC         126 :     pg_logging_init(argv[0]);
 2250 rhaas                     831             126 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump"));
 3698 alvherre                  832 GIC         126 :     progname = get_progname(argv[0]);
 3698 alvherre                  833 EUB             : 
 1404 peter                     834 GBC         126 :     if (argc > 1)
 1404 peter                     835 EUB             :     {
 1404 peter                     836 GIC         126 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
 1404 peter                     837 EUB             :         {
 1404 peter                     838 GIC           1 :             usage();
                                839               1 :             exit(0);
                                840                 :         }
                                841             125 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
                                842                 :         {
                                843              79 :             puts("pg_waldump (PostgreSQL) " PG_VERSION);
                                844              79 :             exit(0);
                                845                 :         }
                                846                 :     }
                                847                 : 
  699 tmunro                    848              46 :     memset(&private, 0, sizeof(XLogDumpPrivate));
 3698 alvherre                  849 CBC          46 :     memset(&config, 0, sizeof(XLogDumpConfig));
  366 jdavis                    850 GIC          46 :     memset(&stats, 0, sizeof(XLogStats));
 3698 alvherre                  851 ECB             : 
  699 tmunro                    852 GIC          46 :     private.timeline = 1;
  699 tmunro                    853 CBC          46 :     private.startptr = InvalidXLogRecPtr;
                                854              46 :     private.endptr = InvalidXLogRecPtr;
                                855              46 :     private.endptr_reached = false;
 3698 alvherre                  856 ECB             : 
 1102 rhaas                     857 CBC          46 :     config.quiet = false;
 3698 alvherre                  858              46 :     config.bkp_details = false;
                                859              46 :     config.stop_after_records = -1;
                                860              46 :     config.already_displayed_records = 0;
 3301 heikki.linnakangas        861 GIC          46 :     config.follow = false;
  647 heikki.linnakangas        862 ECB             :     /* filter_by_rmgr array was zeroed by memset above */
  647 heikki.linnakangas        863 CBC          46 :     config.filter_by_rmgr_enabled = false;
 3698 alvherre                  864 GIC          46 :     config.filter_by_xid = InvalidTransactionId;
                                865              46 :     config.filter_by_xid_enabled = false;
  381 tmunro                    866 CBC          46 :     config.filter_by_extended = false;
                                867              46 :     config.filter_by_relation_enabled = false;
  381 tmunro                    868 GIC          46 :     config.filter_by_relation_block_enabled = false;
  381 tmunro                    869 CBC          46 :     config.filter_by_relation_forknum = InvalidForkNumber;
                                870              46 :     config.filter_by_fpw = false;
  103 michael                   871 GNC          46 :     config.save_fullpage_path = NULL;
 3124 andres                    872 CBC          46 :     config.stats = false;
 3124 andres                    873 GIC          46 :     config.stats_per_record = false;
 3698 alvherre                  874 ECB             : 
  493 michael                   875 CBC          46 :     stats.startptr = InvalidXLogRecPtr;
                                876              46 :     stats.endptr = InvalidXLogRecPtr;
                                877                 : 
 3698 alvherre                  878              46 :     if (argc <= 1)
 3698 alvherre                  879 ECB             :     {
 1469 peter                     880 UIC           0 :         pg_log_error("no arguments specified");
 3698 alvherre                  881 LBC           0 :         goto bad_argument;
 3698 alvherre                  882 ECB             :     }
                                883                 : 
  380 tmunro                    884 CBC         269 :     while ((option = getopt_long(argc, argv, "bB:e:fF:n:p:qr:R:s:t:wx:z",
 3698 alvherre                  885 GIC         269 :                                  long_options, &optindex)) != -1)
                                886                 :     {
 3698 alvherre                  887 CBC         224 :         switch (option)
                                888                 :         {
 3698 alvherre                  889 UIC           0 :             case 'b':
                                890               0 :                 config.bkp_details = true;
                                891               0 :                 break;
  380 tmunro                    892               0 :             case 'B':
                                893               0 :                 if (sscanf(optarg, "%u", &config.filter_by_relation_block) != 1 ||
                                894               0 :                     !BlockNumberIsValid(config.filter_by_relation_block))
                                895                 :                 {
  324 peter                     896               0 :                     pg_log_error("invalid block number: \"%s\"", optarg);
  380 tmunro                    897 LBC           0 :                     goto bad_argument;
                                898                 :                 }
  380 tmunro                    899 UIC           0 :                 config.filter_by_relation_block_enabled = true;
                                900               0 :                 config.filter_by_extended = true;
                                901               0 :                 break;
 3698 alvherre                  902 GIC          44 :             case 'e':
                                903              44 :                 if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2)
                                904                 :                 {
  324 peter                     905 UIC           0 :                     pg_log_error("invalid WAL location: \"%s\"",
                                906                 :                                  optarg);
 3698 alvherre                  907               0 :                     goto bad_argument;
                                908                 :                 }
  699 tmunro                    909 GIC          44 :                 private.endptr = (uint64) xlogid << 32 | xrecoff;
 3698 alvherre                  910              44 :                 break;
 3301 heikki.linnakangas        911 UIC           0 :             case 'f':
                                912               0 :                 config.follow = true;
                                913               0 :                 break;
  381 tmunro                    914               0 :             case 'F':
  380                           915               0 :                 config.filter_by_relation_forknum = forkname_to_number(optarg);
                                916               0 :                 if (config.filter_by_relation_forknum == InvalidForkNumber)
                                917                 :                 {
  324 peter                     918               0 :                     pg_log_error("invalid fork name: \"%s\"", optarg);
  381 tmunro                    919               0 :                     goto bad_argument;
                                920                 :                 }
                                921               0 :                 config.filter_by_extended = true;
                                922               0 :                 break;
 3698 alvherre                  923 LBC           0 :             case 'n':
 3698 alvherre                  924 UIC           0 :                 if (sscanf(optarg, "%d", &config.stop_after_records) != 1)
                                925                 :                 {
  324 peter                     926 LBC           0 :                     pg_log_error("invalid value \"%s\" for option %s", optarg, "-n/--limit");
 3698 alvherre                  927 UIC           0 :                     goto bad_argument;
                                928                 :                 }
 3698 alvherre                  929 LBC           0 :                 break;
 3698 alvherre                  930 CBC          44 :             case 'p':
 1293                           931              44 :                 waldir = pg_strdup(optarg);
 3698 alvherre                  932 GIC          44 :                 break;
 1102 rhaas                     933 CBC          45 :             case 'q':
 1102 rhaas                     934 GIC          45 :                 config.quiet = true;
 1102 rhaas                     935 CBC          45 :                 break;
 3698 alvherre                  936 UIC           0 :             case 'r':
 3698 alvherre                  937 ECB             :                 {
  368 jdavis                    938                 :                     int         rmid;
                                939                 : 
 3698 alvherre                  940 LBC           0 :                     if (pg_strcasecmp(optarg, "list") == 0)
                                941                 :                     {
                                942               0 :                         print_rmgr_list();
                                943               0 :                         exit(EXIT_SUCCESS);
                                944                 :                     }
                                945                 : 
                                946                 :                     /*
  368 jdavis                    947 ECB             :                      * First look for the generated name of a custom rmgr, of
                                948                 :                      * the form "custom###". We accept this form, because the
                                949                 :                      * custom rmgr module is not loaded, so there's no way to
                                950                 :                      * know the real name. This convention should be
                                951                 :                      * consistent with that in rmgrdesc.c.
                                952                 :                      */
  368 jdavis                    953 LBC           0 :                     if (sscanf(optarg, "custom%03d", &rmid) == 1)
 3698 alvherre                  954 ECB             :                     {
  367 jdavis                    955 UIC           0 :                         if (!RmgrIdIsCustom(rmid))
 3698 alvherre                  956 ECB             :                         {
  368 jdavis                    957 LBC           0 :                             pg_log_error("custom resource manager \"%s\" does not exist",
  368 jdavis                    958 ECB             :                                          optarg);
  368 jdavis                    959 LBC           0 :                             goto bad_argument;
 3698 alvherre                  960 ECB             :                         }
  368 jdavis                    961 UIC           0 :                         config.filter_by_rmgr[rmid] = true;
  368 jdavis                    962 LBC           0 :                         config.filter_by_rmgr_enabled = true;
 3698 alvherre                  963 ECB             :                     }
  368 jdavis                    964                 :                     else
 3698 alvherre                  965                 :                     {
  368 jdavis                    966                 :                         /* then look for builtin rmgrs */
  368 jdavis                    967 LBC           0 :                         for (rmid = 0; rmid <= RM_MAX_BUILTIN_ID; rmid++)
  368 jdavis                    968 ECB             :                         {
  368 jdavis                    969 LBC           0 :                             if (pg_strcasecmp(optarg, GetRmgrDesc(rmid)->rm_name) == 0)
  368 jdavis                    970 ECB             :                             {
  368 jdavis                    971 LBC           0 :                                 config.filter_by_rmgr[rmid] = true;
                                972               0 :                                 config.filter_by_rmgr_enabled = true;
  368 jdavis                    973 UIC           0 :                                 break;
  368 jdavis                    974 ECB             :                             }
                                975                 :                         }
  368 jdavis                    976 UIC           0 :                         if (rmid > RM_MAX_BUILTIN_ID)
  368 jdavis                    977 ECB             :                         {
  368 jdavis                    978 UIC           0 :                             pg_log_error("resource manager \"%s\" does not exist",
  368 jdavis                    979 EUB             :                                          optarg);
  368 jdavis                    980 UBC           0 :                             goto bad_argument;
                                981                 :                         }
                                982                 :                     }
 3698 alvherre                  983 ECB             :                 }
 3698 alvherre                  984 LBC           0 :                 break;
  380 tmunro                    985 GIC           1 :             case 'R':
  193 rhaas                     986 CBC           1 :                 if (sscanf(optarg, "%u/%u/%u",
                                987                 :                            &config.filter_by_relation.spcOid,
                                988                 :                            &config.filter_by_relation.dbOid,
  277 rhaas                     989 GNC           1 :                            &config.filter_by_relation.relNumber) != 3 ||
                                990               1 :                     !OidIsValid(config.filter_by_relation.spcOid) ||
                                991               1 :                     !RelFileNumberIsValid(config.filter_by_relation.relNumber))
  380 tmunro                    992 EUB             :                 {
  324 peter                     993 UBC           0 :                     pg_log_error("invalid relation specification: \"%s\"", optarg);
  324 peter                     994 UIC           0 :                     pg_log_error_detail("Expecting \"tablespace OID/database OID/relation filenode\".");
  380 tmunro                    995 UBC           0 :                     goto bad_argument;
  380 tmunro                    996 EUB             :                 }
  380 tmunro                    997 GIC           1 :                 config.filter_by_relation_enabled = true;
  380 tmunro                    998 GBC           1 :                 config.filter_by_extended = true;
                                999               1 :                 break;
 3698 alvherre                 1000              44 :             case 's':
 3698 alvherre                 1001 CBC          44 :                 if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2)
 3698 alvherre                 1002 ECB             :                 {
  324 peter                    1003 UIC           0 :                     pg_log_error("invalid WAL location: \"%s\"",
 1469 peter                    1004 EUB             :                                  optarg);
 3698 alvherre                 1005 UIC           0 :                     goto bad_argument;
 3698 alvherre                 1006 EUB             :                 }
                               1007                 :                 else
  699 tmunro                   1008 CBC          44 :                     private.startptr = (uint64) xlogid << 32 | xrecoff;
 3698 alvherre                 1009              44 :                 break;
 3698 alvherre                 1010 GBC          44 :             case 't':
                               1011                 : 
                               1012                 :                 /*
                               1013                 :                  * This is like option_parse_int() but needs to handle
                               1014                 :                  * unsigned 32-bit int.  Also, we accept both decimal and
                               1015                 :                  * hexadecimal specifications here.
                               1016                 :                  */
 3698 alvherre                 1017 EUB             :                 {
                               1018                 :                     char       *endptr;
                               1019                 :                     unsigned long val;
                               1020                 : 
   19 peter                    1021 GNC          44 :                     errno = 0;
                               1022              44 :                     val = strtoul(optarg, &endptr, 0);
                               1023                 : 
                               1024              44 :                     while (*endptr != '\0' && isspace((unsigned char) *endptr))
   19 peter                    1025 UNC           0 :                         endptr++;
                               1026                 : 
   19 peter                    1027 GNC          44 :                     if (*endptr != '\0')
                               1028                 :                     {
   19 peter                    1029 UNC           0 :                         pg_log_error("invalid value \"%s\" for option %s",
                               1030                 :                                      optarg, "-t/--timeline");
                               1031               0 :                         goto bad_argument;
                               1032                 :                     }
                               1033                 : 
   19 peter                    1034 GNC          44 :                     if (errno == ERANGE || val < 1 || val > UINT_MAX)
                               1035                 :                     {
   19 peter                    1036 UNC           0 :                         pg_log_error("%s must be in range %u..%u",
                               1037                 :                                      "-t/--timeline", 1, UINT_MAX);
                               1038               0 :                         goto bad_argument;
                               1039                 :                     }
                               1040                 : 
   19 peter                    1041 GNC          44 :                     private.timeline = val;
                               1042                 : 
                               1043              44 :                     break;
 3698 alvherre                 1044 EUB             :                 }
  381 tmunro                   1045 UBC           0 :             case 'w':
                               1046               0 :                 config.filter_by_fpw = true;
  381 tmunro                   1047 UIC           0 :                 break;
 3698 alvherre                 1048 UBC           0 :             case 'x':
                               1049               0 :                 if (sscanf(optarg, "%u", &config.filter_by_xid) != 1)
 3698 alvherre                 1050 EUB             :                 {
  324 peter                    1051 UBC           0 :                     pg_log_error("invalid transaction ID specification: \"%s\"",
                               1052                 :                                  optarg);
 3698 alvherre                 1053               0 :                     goto bad_argument;
 3698 alvherre                 1054 EUB             :                 }
 3698 alvherre                 1055 UIC           0 :                 config.filter_by_xid_enabled = true;
 3698 alvherre                 1056 UBC           0 :                 break;
 3124 andres                   1057 LBC           0 :             case 'z':
                               1058               0 :                 config.stats = true;
                               1059               0 :                 config.stats_per_record = false;
                               1060               0 :                 if (optarg)
 3124 andres                   1061 ECB             :                 {
 3124 andres                   1062 LBC           0 :                     if (strcmp(optarg, "record") == 0)
 3124 andres                   1063 UBC           0 :                         config.stats_per_record = true;
 3124 andres                   1064 UIC           0 :                     else if (strcmp(optarg, "rmgr") != 0)
                               1065                 :                     {
  324 peter                    1066               0 :                         pg_log_error("unrecognized value for option %s: %s",
  324 peter                    1067 EUB             :                                      "--stats", optarg);
 3124 andres                   1068 UIC           0 :                         goto bad_argument;
 3124 andres                   1069 EUB             :                     }
                               1070                 :                 }
 3124 andres                   1071 UIC           0 :                 break;
  103 michael                  1072 GNC           1 :             case 1:
                               1073               1 :                 config.save_fullpage_path = pg_strdup(optarg);
                               1074               1 :                 break;
 3698 alvherre                 1075 GIC           1 :             default:
                               1076               1 :                 goto bad_argument;
                               1077                 :         }
                               1078                 :     }
                               1079                 : 
  381 tmunro                   1080              45 :     if (config.filter_by_relation_block_enabled &&
  381 tmunro                   1081 UIC           0 :         !config.filter_by_relation_enabled)
                               1082                 :     {
  324 peter                    1083 UBC           0 :         pg_log_error("option %s requires option %s to be specified",
                               1084                 :                      "-B/--block", "-R/--relation");
  381 tmunro                   1085               0 :         goto bad_argument;
                               1086                 :     }
  381 tmunro                   1087 EUB             : 
 3698 alvherre                 1088 GIC          45 :     if ((optind + 2) < argc)
 3698 alvherre                 1089 EUB             :     {
 1469 peter                    1090 UIC           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
 1469 peter                    1091 EUB             :                      argv[optind + 2]);
 3698 alvherre                 1092 UBC           0 :         goto bad_argument;
                               1093                 :     }
                               1094                 : 
 1293 alvherre                 1095 GIC          45 :     if (waldir != NULL)
                               1096                 :     {
 3698 alvherre                 1097 EUB             :         /* validate path points to directory */
 1293 alvherre                 1098 GIC          44 :         if (!verify_directory(waldir))
 3698 alvherre                 1099 EUB             :         {
 1202 michael                  1100 GIC           1 :             pg_log_error("could not open directory \"%s\": %m", waldir);
 3698 alvherre                 1101 GBC           1 :             goto bad_argument;
 3698 alvherre                 1102 EUB             :         }
                               1103                 :     }
                               1104                 : 
  103 michael                  1105 GNC          44 :     if (config.save_fullpage_path != NULL)
                               1106               1 :         create_fullpage_directory(config.save_fullpage_path);
                               1107                 : 
                               1108                 :     /* parse files as start/end boundaries, extract path if not specified */
 3698 alvherre                 1109 GBC          44 :     if (optind < argc)
                               1110                 :     {
                               1111               1 :         char       *directory = NULL;
 3698 alvherre                 1112 GIC           1 :         char       *fname = NULL;
 3698 alvherre                 1113 EUB             :         int         fd;
                               1114                 :         XLogSegNo   segno;
                               1115                 : 
 3698 alvherre                 1116 GIC           1 :         split_path(argv[optind], &directory, &fname);
 3698 alvherre                 1117 EUB             : 
 1293 alvherre                 1118 CBC           1 :         if (waldir == NULL && directory != NULL)
 3698 alvherre                 1119 ECB             :         {
 1293 alvherre                 1120 GIC           1 :             waldir = directory;
                               1121                 : 
 1293 alvherre                 1122 CBC           1 :             if (!verify_directory(waldir))
  366 tgl                      1123 LBC           0 :                 pg_fatal("could not open directory \"%s\": %m", waldir);
 3698 alvherre                 1124 ECB             :         }
                               1125                 : 
 1293 alvherre                 1126 GBC           1 :         waldir = identify_target_directory(waldir, fname);
                               1127               1 :         fd = open_file_in_directory(waldir, fname);
 3698                          1128               1 :         if (fd < 0)
  366 tgl                      1129 UIC           0 :             pg_fatal("could not open file \"%s\"", fname);
 3698 alvherre                 1130 CBC           1 :         close(fd);
 3698 alvherre                 1131 ECB             : 
                               1132                 :         /* parse position from file */
  699 tmunro                   1133 CBC           1 :         XLogFromFileName(fname, &private.timeline, &segno, WalSegSz);
 3698 alvherre                 1134 ECB             : 
  699 tmunro                   1135 GIC           1 :         if (XLogRecPtrIsInvalid(private.startptr))
  699 tmunro                   1136 GBC           1 :             XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr);
  699 tmunro                   1137 UIC           0 :         else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
 3698 alvherre                 1138 EUB             :         {
 1469 peter                    1139 UIC           0 :             pg_log_error("start WAL location %X/%X is not inside file \"%s\"",
                               1140                 :                          LSN_FORMAT_ARGS(private.startptr),
 1418 tgl                      1141 ECB             :                          fname);
 3698 alvherre                 1142 LBC           0 :             goto bad_argument;
 3698 alvherre                 1143 ECB             :         }
                               1144                 : 
                               1145                 :         /* no second file specified, set end position */
  699 tmunro                   1146 GIC           1 :         if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr))
                               1147               1 :             XLogSegNoOffsetToRecPtr(segno + 1, 0, WalSegSz, private.endptr);
                               1148                 : 
                               1149                 :         /* parse ENDSEG if passed */
 3698 alvherre                 1150               1 :         if (optind + 1 < argc)
                               1151                 :         {
                               1152                 :             XLogSegNo   endsegno;
                               1153                 : 
 3698 alvherre                 1154 ECB             :             /* ignore directory, already have that */
 3698 alvherre                 1155 LBC           0 :             split_path(argv[optind + 1], &directory, &fname);
                               1156                 : 
 1293                          1157               0 :             fd = open_file_in_directory(waldir, fname);
 3698 alvherre                 1158 UBC           0 :             if (fd < 0)
  366 tgl                      1159 UIC           0 :                 pg_fatal("could not open file \"%s\"", fname);
 3698 alvherre                 1160 LBC           0 :             close(fd);
                               1161                 : 
 3698 alvherre                 1162 EUB             :             /* parse position from file */
  699 tmunro                   1163 UIC           0 :             XLogFromFileName(fname, &private.timeline, &endsegno, WalSegSz);
 3698 alvherre                 1164 EUB             : 
 3698 alvherre                 1165 UIC           0 :             if (endsegno < segno)
  366 tgl                      1166               0 :                 pg_fatal("ENDSEG %s is before STARTSEG %s",
  366 tgl                      1167 ECB             :                          argv[optind + 1], argv[optind]);
                               1168                 : 
  699 tmunro                   1169 UBC           0 :             if (XLogRecPtrIsInvalid(private.endptr))
 1735 alvherre                 1170 UIC           0 :                 XLogSegNoOffsetToRecPtr(endsegno + 1, 0, WalSegSz,
  699 tmunro                   1171 EUB             :                                         private.endptr);
                               1172                 : 
                               1173                 :             /* set segno to endsegno for check of --end */
 3698 alvherre                 1174 LBC           0 :             segno = endsegno;
                               1175                 :         }
 3698 alvherre                 1176 ECB             : 
                               1177                 : 
  699 tmunro                   1178 GBC           1 :         if (!XLByteInSeg(private.endptr, segno, WalSegSz) &&
                               1179               1 :             private.endptr != (segno + 1) * WalSegSz)
 3698 alvherre                 1180 EUB             :         {
 1469 peter                    1181 UBC           0 :             pg_log_error("end WAL location %X/%X is not inside file \"%s\"",
  699 tmunro                   1182 EUB             :                          LSN_FORMAT_ARGS(private.endptr),
                               1183                 :                          argv[argc - 1]);
 3698 alvherre                 1184 UBC           0 :             goto bad_argument;
                               1185                 :         }
 3698 alvherre                 1186 EUB             :     }
                               1187                 :     else
 1293 alvherre                 1188 GBC          43 :         waldir = identify_target_directory(waldir, NULL);
 3698 alvherre                 1189 EUB             : 
                               1190                 :     /* we don't know what to print */
  699 tmunro                   1191 GBC          43 :     if (XLogRecPtrIsInvalid(private.startptr))
 3698 alvherre                 1192 EUB             :     {
 1469 peter                    1193 UBC           0 :         pg_log_error("no start WAL location given");
 3698 alvherre                 1194 UIC           0 :         goto bad_argument;
 3698 alvherre                 1195 EUB             :     }
                               1196                 : 
                               1197                 :     /* done with argument parsing, do the actual work */
                               1198                 : 
                               1199                 :     /* we have everything we need, start reading */
                               1200                 :     xlogreader_state =
  699 tmunro                   1201 GBC          43 :         XLogReaderAllocate(WalSegSz, waldir,
  699 tmunro                   1202 GIC          43 :                            XL_ROUTINE(.page_read = WALDumpReadPage,
                               1203                 :                                       .segment_open = WALDumpOpenSegment,
  699 tmunro                   1204 EUB             :                                       .segment_close = WALDumpCloseSegment),
  699 tmunro                   1205 ECB             :                            &private);
 3698 alvherre                 1206 CBC          43 :     if (!xlogreader_state)
  366 tgl                      1207 LBC           0 :         pg_fatal("out of memory while allocating a WAL reading processor");
 3698 alvherre                 1208 ECB             : 
                               1209                 :     /* first find a valid recptr to start from */
  699 tmunro                   1210 GIC          43 :     first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
                               1211                 : 
 3698 alvherre                 1212              43 :     if (first_record == InvalidXLogRecPtr)
  366 tgl                      1213 LBC           0 :         pg_fatal("could not find a valid record after %X/%X",
  366 tgl                      1214 EUB             :                  LSN_FORMAT_ARGS(private.startptr));
                               1215                 : 
 3698 alvherre                 1216                 :     /*
                               1217                 :      * Display a message that we're skipping data if `from` wasn't a pointer
 3602 bruce                    1218                 :      * to the start of a record and also wasn't a pointer to the beginning of
                               1219                 :      * a segment (e.g. we were used in file mode).
                               1220                 :      */
  699 tmunro                   1221 CBC          43 :     if (first_record != private.startptr &&
  699 tmunro                   1222 GIC           1 :         XLogSegmentOffset(private.startptr, WalSegSz) != 0)
 2053 peter_e                  1223 UBC           0 :         printf(ngettext("first record is after %X/%X, at %X/%X, skipping over %u byte\n",
                               1224                 :                         "first record is after %X/%X, at %X/%X, skipping over %u bytes\n",
  699 tmunro                   1225 EUB             :                         (first_record - private.startptr)),
                               1226                 :                LSN_FORMAT_ARGS(private.startptr),
                               1227                 :                LSN_FORMAT_ARGS(first_record),
  699 tmunro                   1228 ECB             :                (uint32) (first_record - private.startptr));
                               1229                 : 
  493 michael                  1230 GIC          43 :     if (config.stats == true && !config.quiet)
  493 michael                  1231 LBC           0 :         stats.startptr = first_record;
                               1232                 : 
 3301 heikki.linnakangas       1233 ECB             :     for (;;)
 3698 alvherre                 1234                 :     {
  493 michael                  1235 GIC       25909 :         if (time_to_stop)
                               1236                 :         {
                               1237                 :             /* We've been Ctrl-C'ed, so leave */
  493 michael                  1238 LBC           0 :             break;
  493 michael                  1239 ECB             :         }
                               1240                 : 
                               1241                 :         /* try to read the next record */
  699 tmunro                   1242 CBC       25909 :         record = XLogReadRecord(xlogreader_state, &errormsg);
 3301 heikki.linnakangas       1243 GIC       25909 :         if (!record)
 3301 heikki.linnakangas       1244 ECB             :         {
  699 tmunro                   1245 CBC          43 :             if (!config.follow || private.endptr_reached)
                               1246                 :                 break;
                               1247                 :             else
                               1248                 :             {
 3260 bruce                    1249 LBC           0 :                 pg_usleep(1000000L);    /* 1 second */
 3301 heikki.linnakangas       1250 UIC           0 :                 continue;
 3301 heikki.linnakangas       1251 ECB             :             }
                               1252                 :         }
                               1253                 : 
                               1254                 :         /* apply all specified filters */
  647 heikki.linnakangas       1255 CBC       25866 :         if (config.filter_by_rmgr_enabled &&
  647 heikki.linnakangas       1256 UBC           0 :             !config.filter_by_rmgr[record->xl_rmid])
 3124 andres                   1257 UIC           0 :             continue;
                               1258                 : 
 3124 andres                   1259 CBC       25866 :         if (config.filter_by_xid_enabled &&
 3124 andres                   1260 LBC           0 :             config.filter_by_xid != record->xl_xid)
                               1261               0 :             continue;
 3124 andres                   1262 EUB             : 
  381 tmunro                   1263 ECB             :         /* check for extended filtering */
  381 tmunro                   1264 GIC       25866 :         if (config.filter_by_extended &&
                               1265           51480 :             !XLogRecordMatchesRelationBlock(xlogreader_state,
  381 tmunro                   1266 CBC       25740 :                                             config.filter_by_relation_enabled ?
                               1267                 :                                             config.filter_by_relation :
                               1268                 :                                             emptyRelFileLocator,
                               1269           25740 :                                             config.filter_by_relation_block_enabled ?
  381 tmunro                   1270 EUB             :                                             config.filter_by_relation_block :
                               1271                 :                                             InvalidBlockNumber,
                               1272                 :                                             config.filter_by_relation_forknum))
  381 tmunro                   1273 GIC       25540 :             continue;
                               1274                 : 
  381 tmunro                   1275 GBC         326 :         if (config.filter_by_fpw && !XLogRecordHasFPW(xlogreader_state))
  381 tmunro                   1276 UIC           0 :             continue;
                               1277                 : 
                               1278                 :         /* perform any per-record work */
 1102 rhaas                    1279 CBC         326 :         if (!config.quiet)
 1102 rhaas                    1280 ECB             :         {
 1102 rhaas                    1281 UIC           0 :             if (config.stats == true)
                               1282                 :             {
  366 jdavis                   1283 LBC           0 :                 XLogRecStoreStats(&stats, xlogreader_state);
  493 michael                  1284 UIC           0 :                 stats.endptr = xlogreader_state->EndRecPtr;
                               1285                 :             }
                               1286                 :             else
 1102 rhaas                    1287               0 :                 XLogDumpDisplayRecord(&config, xlogreader_state);
 1102 rhaas                    1288 EUB             :         }
                               1289                 : 
                               1290                 :         /* save full pages if requested */
  103 michael                  1291 GNC         326 :         if (config.save_fullpage_path != NULL)
                               1292             200 :             XLogRecordSaveFPWs(xlogreader_state, config.save_fullpage_path);
                               1293                 : 
 3698 alvherre                 1294 EUB             :         /* check whether we printed enough */
 3124 andres                   1295 GBC         326 :         config.already_displayed_records++;
 3698 alvherre                 1296             326 :         if (config.stop_after_records > 0 &&
 3698 alvherre                 1297 UBC           0 :             config.already_displayed_records >= config.stop_after_records)
 3698 alvherre                 1298 UIC           0 :             break;
                               1299                 :     }
 3698 alvherre                 1300 EUB             : 
 1101 rhaas                    1301 GIC          43 :     if (config.stats == true && !config.quiet)
 3124 andres                   1302 UBC           0 :         XLogDumpDisplayStats(&config, &stats);
 3124 andres                   1303 EUB             : 
  493 michael                  1304 GIC          43 :     if (time_to_stop)
  493 michael                  1305 UIC           0 :         exit(0);
  493 michael                  1306 EUB             : 
 3698 alvherre                 1307 GBC          43 :     if (errormsg)
  366 tgl                      1308 UIC           0 :         pg_fatal("error in WAL record at %X/%X: %s",
                               1309                 :                  LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),
                               1310                 :                  errormsg);
 3698 alvherre                 1311 EUB             : 
 3698 alvherre                 1312 GIC          43 :     XLogReaderFree(xlogreader_state);
                               1313                 : 
                               1314              43 :     return EXIT_SUCCESS;
 3698 alvherre                 1315 ECB             : 
 3698 alvherre                 1316 CBC           2 : bad_argument:
  366 tgl                      1317 GIC           2 :     pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 3698 alvherre                 1318 GBC           2 :     return EXIT_FAILURE;
                               1319                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a