LCOV - code coverage report
Current view: top level - src/bin/pg_walsummary - pg_walsummary.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 108 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 6 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pg_walsummary.c
       4              :  *              Prints the contents of WAL summary files.
       5              :  *
       6              :  * Copyright (c) 2017-2026, PostgreSQL Global Development Group
       7              :  *
       8              :  * IDENTIFICATION
       9              :  *        src/bin/pg_walsummary/pg_walsummary.c
      10              :  *
      11              :  *-------------------------------------------------------------------------
      12              :  */
      13              : #include "postgres_fe.h"
      14              : 
      15              : #include <fcntl.h>
      16              : #include <limits.h>
      17              : 
      18              : #include "common/blkreftable.h"
      19              : #include "common/int.h"
      20              : #include "common/logging.h"
      21              : #include "fe_utils/option_utils.h"
      22              : #include "getopt_long.h"
      23              : 
      24              : typedef struct ws_options
      25              : {
      26              :         bool            individual;
      27              :         bool            quiet;
      28              : } ws_options;
      29              : 
      30              : typedef struct ws_file_info
      31              : {
      32              :         int                     fd;
      33              :         char       *filename;
      34              : } ws_file_info;
      35              : 
      36              : static BlockNumber *block_buffer = NULL;
      37              : static unsigned block_buffer_size = 512;        /* Initial size. */
      38              : 
      39              : static void dump_one_relation(ws_options *opt, RelFileLocator *rlocator,
      40              :                                                           ForkNumber forknum, BlockNumber limit_block,
      41              :                                                           BlockRefTableReader *reader);
      42              : static void help(const char *progname);
      43              : static int      compare_block_numbers(const void *a, const void *b);
      44              : static int      walsummary_read_callback(void *callback_arg, void *data,
      45              :                                                                          int length);
      46              : static void walsummary_error_callback(void *callback_arg, char *fmt,...) pg_attribute_printf(2, 3);
      47              : 
      48              : /*
      49              :  * Main program.
      50              :  */
      51              : int
      52            0 : main(int argc, char *argv[])
      53              : {
      54              :         static struct option long_options[] = {
      55              :                 {"individual", no_argument, NULL, 'i'},
      56              :                 {"quiet", no_argument, NULL, 'q'},
      57              :                 {NULL, 0, NULL, 0}
      58              :         };
      59              : 
      60            0 :         const char *progname;
      61            0 :         int                     optindex;
      62            0 :         int                     c;
      63            0 :         ws_options      opt;
      64              : 
      65            0 :         memset(&opt, 0, sizeof(ws_options));
      66              : 
      67            0 :         pg_logging_init(argv[0]);
      68            0 :         progname = get_progname(argv[0]);
      69            0 :         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_walsummary"));
      70            0 :         handle_help_version_opts(argc, argv, progname, help);
      71              : 
      72              :         /* process command-line options */
      73            0 :         while ((c = getopt_long(argc, argv, "iq",
      74            0 :                                                         long_options, &optindex)) != -1)
      75              :         {
      76            0 :                 switch (c)
      77              :                 {
      78              :                         case 'i':
      79            0 :                                 opt.individual = true;
      80            0 :                                 break;
      81              :                         case 'q':
      82            0 :                                 opt.quiet = true;
      83            0 :                                 break;
      84              :                         default:
      85              :                                 /* getopt_long already emitted a complaint */
      86            0 :                                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
      87            0 :                                 exit(1);
      88              :                 }
      89              :         }
      90              : 
      91            0 :         if (optind >= argc)
      92              :         {
      93            0 :                 pg_log_error("no input files specified");
      94            0 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
      95            0 :                 exit(1);
      96              :         }
      97              : 
      98            0 :         while (optind < argc)
      99              :         {
     100            0 :                 ws_file_info ws;
     101            0 :                 BlockRefTableReader *reader;
     102            0 :                 RelFileLocator rlocator;
     103            0 :                 ForkNumber      forknum;
     104            0 :                 BlockNumber limit_block;
     105              : 
     106            0 :                 ws.filename = argv[optind++];
     107            0 :                 if ((ws.fd = open(ws.filename, O_RDONLY | PG_BINARY, 0)) < 0)
     108            0 :                         pg_fatal("could not open file \"%s\": %m", ws.filename);
     109              : 
     110            0 :                 reader = CreateBlockRefTableReader(walsummary_read_callback, &ws,
     111            0 :                                                                                    ws.filename,
     112              :                                                                                    walsummary_error_callback, NULL);
     113            0 :                 while (BlockRefTableReaderNextRelation(reader, &rlocator, &forknum,
     114              :                                                                                            &limit_block))
     115            0 :                         dump_one_relation(&opt, &rlocator, forknum, limit_block, reader);
     116              : 
     117            0 :                 DestroyBlockRefTableReader(reader);
     118            0 :                 close(ws.fd);
     119            0 :         }
     120              : 
     121            0 :         exit(0);
     122              : }
     123              : 
     124              : /*
     125              :  * Dump details for one relation.
     126              :  */
     127              : static void
     128            0 : dump_one_relation(ws_options *opt, RelFileLocator *rlocator,
     129              :                                   ForkNumber forknum, BlockNumber limit_block,
     130              :                                   BlockRefTableReader *reader)
     131              : {
     132            0 :         unsigned        i = 0;
     133            0 :         unsigned        nblocks;
     134            0 :         BlockNumber startblock = InvalidBlockNumber;
     135            0 :         BlockNumber endblock = InvalidBlockNumber;
     136              : 
     137              :         /* Dump limit block, if any. */
     138            0 :         if (limit_block != InvalidBlockNumber)
     139            0 :                 printf("TS %u, DB %u, REL %u, FORK %s: limit %u\n",
     140              :                            rlocator->spcOid, rlocator->dbOid, rlocator->relNumber,
     141              :                            forkNames[forknum], limit_block);
     142              : 
     143              :         /* If we haven't allocated a block buffer yet, do that now. */
     144            0 :         if (block_buffer == NULL)
     145            0 :                 block_buffer = palloc_array(BlockNumber, block_buffer_size);
     146              : 
     147              :         /* Try to fill the block buffer. */
     148            0 :         nblocks = BlockRefTableReaderGetBlocks(reader,
     149            0 :                                                                                    block_buffer,
     150            0 :                                                                                    block_buffer_size);
     151              : 
     152              :         /* If we filled the block buffer completely, we must enlarge it. */
     153            0 :         while (nblocks >= block_buffer_size)
     154              :         {
     155            0 :                 unsigned        new_size;
     156              : 
     157              :                 /* Double the size, being careful about overflow. */
     158            0 :                 new_size = block_buffer_size * 2;
     159            0 :                 if (new_size < block_buffer_size)
     160            0 :                         new_size = PG_UINT32_MAX;
     161            0 :                 block_buffer = repalloc_array(block_buffer, BlockNumber, new_size);
     162              : 
     163              :                 /* Try to fill the newly-allocated space. */
     164            0 :                 nblocks +=
     165            0 :                         BlockRefTableReaderGetBlocks(reader,
     166            0 :                                                                                  block_buffer + block_buffer_size,
     167            0 :                                                                                  new_size - block_buffer_size);
     168              : 
     169              :                 /* Save the new size for later calls. */
     170            0 :                 block_buffer_size = new_size;
     171            0 :         }
     172              : 
     173              :         /* If we don't need to produce any output, skip the rest of this. */
     174            0 :         if (opt->quiet)
     175            0 :                 return;
     176              : 
     177              :         /*
     178              :          * Sort the returned block numbers. If the block reference table was using
     179              :          * the bitmap representation for a given chunk, the block numbers in that
     180              :          * chunk will already be sorted, but when the array-of-offsets
     181              :          * representation is used, we can receive block numbers here out of order.
     182              :          */
     183            0 :         qsort(block_buffer, nblocks, sizeof(BlockNumber), compare_block_numbers);
     184              : 
     185              :         /* Dump block references. */
     186            0 :         while (i < nblocks)
     187              :         {
     188              :                 /*
     189              :                  * Find the next range of blocks to print, but if --individual was
     190              :                  * specified, then consider each block a separate range.
     191              :                  */
     192            0 :                 startblock = endblock = block_buffer[i++];
     193            0 :                 if (!opt->individual)
     194              :                 {
     195            0 :                         while (i < nblocks && block_buffer[i] == endblock + 1)
     196              :                         {
     197            0 :                                 endblock++;
     198            0 :                                 i++;
     199              :                         }
     200            0 :                 }
     201              : 
     202              :                 /* Format this range of block numbers as a string. */
     203            0 :                 if (startblock == endblock)
     204            0 :                         printf("TS %u, DB %u, REL %u, FORK %s: block %u\n",
     205              :                                    rlocator->spcOid, rlocator->dbOid, rlocator->relNumber,
     206              :                                    forkNames[forknum], startblock);
     207              :                 else
     208            0 :                         printf("TS %u, DB %u, REL %u, FORK %s: blocks %u..%u\n",
     209              :                                    rlocator->spcOid, rlocator->dbOid, rlocator->relNumber,
     210              :                                    forkNames[forknum], startblock, endblock);
     211              :         }
     212            0 : }
     213              : 
     214              : /*
     215              :  * Quicksort comparator for block numbers.
     216              :  */
     217              : static int
     218            0 : compare_block_numbers(const void *a, const void *b)
     219              : {
     220            0 :         BlockNumber aa = *(BlockNumber *) a;
     221            0 :         BlockNumber bb = *(BlockNumber *) b;
     222              : 
     223            0 :         return pg_cmp_u32(aa, bb);
     224            0 : }
     225              : 
     226              : /*
     227              :  * Error callback.
     228              :  */
     229              : void
     230            0 : walsummary_error_callback(void *callback_arg, char *fmt,...)
     231              : {
     232            0 :         va_list         ap;
     233              : 
     234            0 :         va_start(ap, fmt);
     235            0 :         pg_log_generic_v(PG_LOG_ERROR, PG_LOG_PRIMARY, fmt, ap);
     236            0 :         va_end(ap);
     237              : 
     238            0 :         exit(1);
     239              : }
     240              : 
     241              : /*
     242              :  * Read callback.
     243              :  */
     244              : int
     245            0 : walsummary_read_callback(void *callback_arg, void *data, int length)
     246              : {
     247            0 :         ws_file_info *ws = callback_arg;
     248            0 :         int                     rc;
     249              : 
     250            0 :         if ((rc = read(ws->fd, data, length)) < 0)
     251            0 :                 pg_fatal("could not read file \"%s\": %m", ws->filename);
     252              : 
     253            0 :         return rc;
     254            0 : }
     255              : 
     256              : /*
     257              :  * help
     258              :  *
     259              :  * Prints help page for the program
     260              :  *
     261              :  * progname: the name of the executed program, such as "pg_walsummary"
     262              :  */
     263              : static void
     264            0 : help(const char *progname)
     265              : {
     266            0 :         printf(_("%s prints the contents of a WAL summary file.\n\n"), progname);
     267            0 :         printf(_("Usage:\n"));
     268            0 :         printf(_("  %s [OPTION]... FILE...\n"), progname);
     269            0 :         printf(_("\nOptions:\n"));
     270            0 :         printf(_("  -i, --individual          list block numbers individually, not as ranges\n"));
     271            0 :         printf(_("  -q, --quiet               don't print anything, just parse the files\n"));
     272            0 :         printf(_("  -V, --version             output version information, then exit\n"));
     273            0 :         printf(_("  -?, --help                show this help, then exit\n"));
     274              : 
     275            0 :         printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     276            0 :         printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
     277            0 : }
        

Generated by: LCOV version 2.3.2-1