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