PostgreSQL Source Code  git master
pg_waldump.c File Reference
#include "postgres.h"
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include "access/xlogreader.h"
#include "access/xlogrecord.h"
#include "access/xlog_internal.h"
#include "access/transam.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
Include dependency graph for pg_waldump.c:

Go to the source code of this file.

Data Structures

struct  XLogDumpPrivate
 
struct  XLogDumpConfig
 
struct  Stats
 
struct  XLogDumpStats
 

Macros

#define FRONTEND   1
 
#define MAX_XLINFO_TYPES   16
 

Typedefs

typedef struct XLogDumpPrivate XLogDumpPrivate
 
typedef struct XLogDumpConfig XLogDumpConfig
 
typedef struct Stats Stats
 
typedef struct XLogDumpStats XLogDumpStats
 

Functions

static void fatal_error (const char *fmt,...) pg_attribute_printf(1
 
static void print_rmgr_list (void)
 
static bool verify_directory (const char *directory)
 
static void split_path (const char *path, char **dir, char **fname)
 
static int open_file_in_directory (const char *directory, const char *fname)
 
static bool search_directory (const char *directory, const char *fname)
 
static void identify_target_directory (XLogDumpPrivate *private, char *directory, char *fname)
 
static void XLogDumpXLogRead (const char *directory, TimeLineID timeline_id, XLogRecPtr startptr, char *buf, Size count)
 
static int XLogDumpReadPage (XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff, TimeLineID *curFileTLI)
 
static void XLogDumpRecordLen (XLogReaderState *record, uint32 *rec_len, uint32 *fpi_len)
 
static void XLogDumpCountRecord (XLogDumpConfig *config, XLogDumpStats *stats, XLogReaderState *record)
 
static void XLogDumpDisplayRecord (XLogDumpConfig *config, XLogReaderState *record)
 
static void XLogDumpStatsRow (const char *name, uint64 n, uint64 total_count, uint64 rec_len, uint64 total_rec_len, uint64 fpi_len, uint64 total_fpi_len, uint64 tot_len, uint64 total_len)
 
static void XLogDumpDisplayStats (XLogDumpConfig *config, XLogDumpStats *stats)
 
static void usage (void)
 
int main (int argc, char **argv)
 

Variables

static const char * progname
 
static int WalSegSz
 

Macro Definition Documentation

◆ FRONTEND

#define FRONTEND   1

Definition at line 12 of file pg_waldump.c.

◆ MAX_XLINFO_TYPES

#define MAX_XLINFO_TYPES   16

Definition at line 64 of file pg_waldump.c.

Referenced by XLogDumpDisplayStats().

Typedef Documentation

◆ Stats

◆ XLogDumpConfig

◆ XLogDumpPrivate

◆ XLogDumpStats

Function Documentation

◆ fatal_error()

static void static void fatal_error ( const char *  fmt,
  ... 
)
static

Definition at line 79 of file pg_waldump.c.

References _, generate_unaccent_rules::args, EXIT_FAILURE, and progname.

Referenced by identify_target_directory(), main(), open_file_in_directory(), search_directory(), and XLogDumpXLogRead().

80 {
81  va_list args;
82 
83  fflush(stdout);
84 
85  fprintf(stderr, _("%s: FATAL: "), progname);
86  va_start(args, fmt);
87  vfprintf(stderr, _(fmt), args);
88  va_end(args);
89  fputc('\n', stderr);
90 
91  exit(EXIT_FAILURE);
92 }
static const char * progname
Definition: pg_waldump.c:28
#define EXIT_FAILURE
Definition: settings.h:152
#define _(x)
Definition: elog.c:84

◆ identify_target_directory()

static void identify_target_directory ( XLogDumpPrivate private,
char *  directory,
char *  fname 
)
static

Definition at line 256 of file pg_waldump.c.

References datadir, fatal_error(), MAXPGPATH, search_directory(), snprintf(), and XLOGDIR.

Referenced by main().

258 {
259  char fpath[MAXPGPATH];
260 
261  if (directory != NULL)
262  {
263  if (search_directory(directory, fname))
264  {
265  private->inpath = strdup(directory);
266  return;
267  }
268 
269  /* directory / XLOGDIR */
270  snprintf(fpath, MAXPGPATH, "%s/%s", directory, XLOGDIR);
271  if (search_directory(fpath, fname))
272  {
273  private->inpath = strdup(fpath);
274  return;
275  }
276  }
277  else
278  {
279  const char *datadir;
280 
281  /* current directory */
282  if (search_directory(".", fname))
283  {
284  private->inpath = strdup(".");
285  return;
286  }
287  /* XLOGDIR */
288  if (search_directory(XLOGDIR, fname))
289  {
290  private->inpath = strdup(XLOGDIR);
291  return;
292  }
293 
294  datadir = getenv("PGDATA");
295  /* $PGDATA / XLOGDIR */
296  if (datadir != NULL)
297  {
298  snprintf(fpath, MAXPGPATH, "%s/%s", datadir, XLOGDIR);
299  if (search_directory(fpath, fname))
300  {
301  private->inpath = strdup(fpath);
302  return;
303  }
304  }
305  }
306 
307  /* could not locate WAL file */
308  if (fname)
309  fatal_error("could not locate WAL file \"%s\"", fname);
310  else
311  fatal_error("could not find any WAL file");
312 }
static bool search_directory(const char *directory, const char *fname)
Definition: pg_waldump.c:178
static void fatal_error(const char *fmt,...) pg_attribute_printf(1
Definition: pg_waldump.c:79
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define MAXPGPATH
char * datadir
#define XLOGDIR
static const char * directory
Definition: zic.c:575

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 821 of file pg_waldump.c.

References _, XLogDumpConfig::already_displayed_records, XLogDumpConfig::bkp_details, close, directory, XLogDumpPrivate::endptr, EXIT_FAILURE, EXIT_SUCCESS, fatal_error(), fd(), XLogDumpConfig::filter_by_rmgr, XLogDumpConfig::filter_by_xid, XLogDumpConfig::filter_by_xid_enabled, XLogDumpConfig::follow, get_progname(), getopt_long(), i, identify_target_directory(), XLogDumpPrivate::inpath, InvalidTransactionId, InvalidXLogRecPtr, ngettext, no_argument, open_file_in_directory(), optarg, optind, optional_argument, pg_strcasecmp(), pg_strdup(), PG_TEXTDOMAIN, pg_usleep(), print_rmgr_list(), progname, XLogReaderState::ReadRecPtr, required_argument, RM_MAX_ID, RmgrDescTable, set_pglocale_pgservice(), split_path(), XLogDumpPrivate::startptr, XLogDumpConfig::stats, XLogDumpConfig::stats_per_record, XLogDumpConfig::stop_after_records, strerror(), XLogDumpPrivate::timeline, usage(), verify_directory(), WalSegSz, XLogRecord::xl_rmid, XLogRecord::xl_xid, XLByteInSeg, XLogDumpCountRecord(), XLogDumpDisplayRecord(), XLogDumpDisplayStats(), XLogDumpReadPage(), XLogFromFileName, XLogReaderAllocate(), XLogReaderFree(), XLogReadRecord(), XLogRecPtrIsInvalid, XLogSegmentOffset, and XLogSegNoOffsetToRecPtr.

822 {
823  uint32 xlogid;
824  uint32 xrecoff;
825  XLogReaderState *xlogreader_state;
826  XLogDumpPrivate private;
827  XLogDumpConfig config;
828  XLogDumpStats stats;
829  XLogRecord *record;
830  XLogRecPtr first_record;
831  char *errormsg;
832 
833  static struct option long_options[] = {
834  {"bkp-details", no_argument, NULL, 'b'},
835  {"end", required_argument, NULL, 'e'},
836  {"follow", no_argument, NULL, 'f'},
837  {"help", no_argument, NULL, '?'},
838  {"limit", required_argument, NULL, 'n'},
839  {"path", required_argument, NULL, 'p'},
840  {"rmgr", required_argument, NULL, 'r'},
841  {"start", required_argument, NULL, 's'},
842  {"timeline", required_argument, NULL, 't'},
843  {"xid", required_argument, NULL, 'x'},
844  {"version", no_argument, NULL, 'V'},
845  {"stats", optional_argument, NULL, 'z'},
846  {NULL, 0, NULL, 0}
847  };
848 
849  int option;
850  int optindex = 0;
851 
852  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump"));
853  progname = get_progname(argv[0]);
854 
855  memset(&private, 0, sizeof(XLogDumpPrivate));
856  memset(&config, 0, sizeof(XLogDumpConfig));
857  memset(&stats, 0, sizeof(XLogDumpStats));
858 
859  private.timeline = 1;
860  private.startptr = InvalidXLogRecPtr;
861  private.endptr = InvalidXLogRecPtr;
862  private.endptr_reached = false;
863 
864  config.bkp_details = false;
865  config.stop_after_records = -1;
866  config.already_displayed_records = 0;
867  config.follow = false;
868  config.filter_by_rmgr = -1;
870  config.filter_by_xid_enabled = false;
871  config.stats = false;
872  config.stats_per_record = false;
873 
874  if (argc <= 1)
875  {
876  fprintf(stderr, _("%s: no arguments specified\n"), progname);
877  goto bad_argument;
878  }
879 
880  while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:z",
881  long_options, &optindex)) != -1)
882  {
883  switch (option)
884  {
885  case 'b':
886  config.bkp_details = true;
887  break;
888  case 'e':
889  if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2)
890  {
891  fprintf(stderr, _("%s: could not parse end WAL location \"%s\"\n"),
892  progname, optarg);
893  goto bad_argument;
894  }
895  private.endptr = (uint64) xlogid << 32 | xrecoff;
896  break;
897  case 'f':
898  config.follow = true;
899  break;
900  case '?':
901  usage();
902  exit(EXIT_SUCCESS);
903  break;
904  case 'n':
905  if (sscanf(optarg, "%d", &config.stop_after_records) != 1)
906  {
907  fprintf(stderr, _("%s: could not parse limit \"%s\"\n"),
908  progname, optarg);
909  goto bad_argument;
910  }
911  break;
912  case 'p':
913  private.inpath = pg_strdup(optarg);
914  break;
915  case 'r':
916  {
917  int i;
918 
919  if (pg_strcasecmp(optarg, "list") == 0)
920  {
921  print_rmgr_list();
922  exit(EXIT_SUCCESS);
923  }
924 
925  for (i = 0; i <= RM_MAX_ID; i++)
926  {
927  if (pg_strcasecmp(optarg, RmgrDescTable[i].rm_name) == 0)
928  {
929  config.filter_by_rmgr = i;
930  break;
931  }
932  }
933 
934  if (config.filter_by_rmgr == -1)
935  {
936  fprintf(stderr, _("%s: resource manager \"%s\" does not exist\n"),
937  progname, optarg);
938  goto bad_argument;
939  }
940  }
941  break;
942  case 's':
943  if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2)
944  {
945  fprintf(stderr, _("%s: could not parse start WAL location \"%s\"\n"),
946  progname, optarg);
947  goto bad_argument;
948  }
949  else
950  private.startptr = (uint64) xlogid << 32 | xrecoff;
951  break;
952  case 't':
953  if (sscanf(optarg, "%d", &private.timeline) != 1)
954  {
955  fprintf(stderr, _("%s: could not parse timeline \"%s\"\n"),
956  progname, optarg);
957  goto bad_argument;
958  }
959  break;
960  case 'V':
961  puts("pg_waldump (PostgreSQL) " PG_VERSION);
962  exit(EXIT_SUCCESS);
963  break;
964  case 'x':
965  if (sscanf(optarg, "%u", &config.filter_by_xid) != 1)
966  {
967  fprintf(stderr, _("%s: could not parse \"%s\" as a transaction ID\n"),
968  progname, optarg);
969  goto bad_argument;
970  }
971  config.filter_by_xid_enabled = true;
972  break;
973  case 'z':
974  config.stats = true;
975  config.stats_per_record = false;
976  if (optarg)
977  {
978  if (strcmp(optarg, "record") == 0)
979  config.stats_per_record = true;
980  else if (strcmp(optarg, "rmgr") != 0)
981  {
982  fprintf(stderr, _("%s: unrecognized argument to --stats: %s\n"),
983  progname, optarg);
984  goto bad_argument;
985  }
986  }
987  break;
988  default:
989  goto bad_argument;
990  }
991  }
992 
993  if ((optind + 2) < argc)
994  {
995  fprintf(stderr,
996  _("%s: too many command-line arguments (first is \"%s\")\n"),
997  progname, argv[optind + 2]);
998  goto bad_argument;
999  }
1000 
1001  if (private.inpath != NULL)
1002  {
1003  /* validate path points to directory */
1004  if (!verify_directory(private.inpath))
1005  {
1006  fprintf(stderr,
1007  _("%s: path \"%s\" could not be opened: %s\n"),
1008  progname, private.inpath, strerror(errno));
1009  goto bad_argument;
1010  }
1011  }
1012 
1013  /* parse files as start/end boundaries, extract path if not specified */
1014  if (optind < argc)
1015  {
1016  char *directory = NULL;
1017  char *fname = NULL;
1018  int fd;
1019  XLogSegNo segno;
1020 
1021  split_path(argv[optind], &directory, &fname);
1022 
1023  if (private.inpath == NULL && directory != NULL)
1024  {
1025  private.inpath = directory;
1026 
1027  if (!verify_directory(private.inpath))
1028  fatal_error("could not open directory \"%s\": %s",
1029  private.inpath, strerror(errno));
1030  }
1031 
1032  identify_target_directory(&private, private.inpath, fname);
1033  fd = open_file_in_directory(private.inpath, fname);
1034  if (fd < 0)
1035  fatal_error("could not open file \"%s\"", fname);
1036  close(fd);
1037 
1038  /* parse position from file */
1039  XLogFromFileName(fname, &private.timeline, &segno, WalSegSz);
1040 
1041  if (XLogRecPtrIsInvalid(private.startptr))
1042  XLogSegNoOffsetToRecPtr(segno, 0, private.startptr, WalSegSz);
1043  else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
1044  {
1045  fprintf(stderr,
1046  _("%s: start WAL location %X/%X is not inside file \"%s\"\n"),
1047  progname,
1048  (uint32) (private.startptr >> 32),
1049  (uint32) private.startptr,
1050  fname);
1051  goto bad_argument;
1052  }
1053 
1054  /* no second file specified, set end position */
1055  if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr))
1056  XLogSegNoOffsetToRecPtr(segno + 1, 0, private.endptr, WalSegSz);
1057 
1058  /* parse ENDSEG if passed */
1059  if (optind + 1 < argc)
1060  {
1061  XLogSegNo endsegno;
1062 
1063  /* ignore directory, already have that */
1064  split_path(argv[optind + 1], &directory, &fname);
1065 
1066  fd = open_file_in_directory(private.inpath, fname);
1067  if (fd < 0)
1068  fatal_error("could not open file \"%s\"", fname);
1069  close(fd);
1070 
1071  /* parse position from file */
1072  XLogFromFileName(fname, &private.timeline, &endsegno, WalSegSz);
1073 
1074  if (endsegno < segno)
1075  fatal_error("ENDSEG %s is before STARTSEG %s",
1076  argv[optind + 1], argv[optind]);
1077 
1078  if (XLogRecPtrIsInvalid(private.endptr))
1079  XLogSegNoOffsetToRecPtr(endsegno + 1, 0, private.endptr,
1080  WalSegSz);
1081 
1082  /* set segno to endsegno for check of --end */
1083  segno = endsegno;
1084  }
1085 
1086 
1087  if (!XLByteInSeg(private.endptr, segno, WalSegSz) &&
1088  private.endptr != (segno + 1) * WalSegSz)
1089  {
1090  fprintf(stderr,
1091  _("%s: end WAL location %X/%X is not inside file \"%s\"\n"),
1092  progname,
1093  (uint32) (private.endptr >> 32),
1094  (uint32) private.endptr,
1095  argv[argc - 1]);
1096  goto bad_argument;
1097  }
1098  }
1099  else
1100  identify_target_directory(&private, private.inpath, NULL);
1101 
1102  /* we don't know what to print */
1103  if (XLogRecPtrIsInvalid(private.startptr))
1104  {
1105  fprintf(stderr, _("%s: no start WAL location given\n"), progname);
1106  goto bad_argument;
1107  }
1108 
1109  /* done with argument parsing, do the actual work */
1110 
1111  /* we have everything we need, start reading */
1112  xlogreader_state = XLogReaderAllocate(WalSegSz, XLogDumpReadPage,
1113  &private);
1114  if (!xlogreader_state)
1115  fatal_error("out of memory");
1116 
1117  /* first find a valid recptr to start from */
1118  first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
1119 
1120  if (first_record == InvalidXLogRecPtr)
1121  fatal_error("could not find a valid record after %X/%X",
1122  (uint32) (private.startptr >> 32),
1123  (uint32) private.startptr);
1124 
1125  /*
1126  * Display a message that we're skipping data if `from` wasn't a pointer
1127  * to the start of a record and also wasn't a pointer to the beginning of
1128  * a segment (e.g. we were used in file mode).
1129  */
1130  if (first_record != private.startptr &&
1131  XLogSegmentOffset(private.startptr, WalSegSz) != 0)
1132  printf(ngettext("first record is after %X/%X, at %X/%X, skipping over %u byte\n",
1133  "first record is after %X/%X, at %X/%X, skipping over %u bytes\n",
1134  (first_record - private.startptr)),
1135  (uint32) (private.startptr >> 32), (uint32) private.startptr,
1136  (uint32) (first_record >> 32), (uint32) first_record,
1137  (uint32) (first_record - private.startptr));
1138 
1139  for (;;)
1140  {
1141  /* try to read the next record */
1142  record = XLogReadRecord(xlogreader_state, first_record, &errormsg);
1143  if (!record)
1144  {
1145  if (!config.follow || private.endptr_reached)
1146  break;
1147  else
1148  {
1149  pg_usleep(1000000L); /* 1 second */
1150  continue;
1151  }
1152  }
1153 
1154  /* after reading the first record, continue at next one */
1155  first_record = InvalidXLogRecPtr;
1156 
1157  /* apply all specified filters */
1158  if (config.filter_by_rmgr != -1 &&
1159  config.filter_by_rmgr != record->xl_rmid)
1160  continue;
1161 
1162  if (config.filter_by_xid_enabled &&
1163  config.filter_by_xid != record->xl_xid)
1164  continue;
1165 
1166  /* process the record */
1167  if (config.stats == true)
1168  XLogDumpCountRecord(&config, &stats, xlogreader_state);
1169  else
1170  XLogDumpDisplayRecord(&config, xlogreader_state);
1171 
1172  /* check whether we printed enough */
1173  config.already_displayed_records++;
1174  if (config.stop_after_records > 0 &&
1176  break;
1177  }
1178 
1179  if (config.stats == true)
1180  XLogDumpDisplayStats(&config, &stats);
1181 
1182  if (errormsg)
1183  fatal_error("error in WAL record at %X/%X: %s",
1184  (uint32) (xlogreader_state->ReadRecPtr >> 32),
1185  (uint32) xlogreader_state->ReadRecPtr,
1186  errormsg);
1187 
1188  XLogReaderFree(xlogreader_state);
1189 
1190  return EXIT_SUCCESS;
1191 
1192 bad_argument:
1193  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
1194  return EXIT_FAILURE;
1195 }
static void usage(void)
Definition: pg_waldump.c:794
static void XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
Definition: pg_waldump.c:679
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
int already_displayed_records
Definition: pg_waldump.c:46
#define EXIT_SUCCESS
Definition: settings.h:148
int filter_by_rmgr
Definition: pg_waldump.c:52
const char * get_progname(const char *argv0)
Definition: path.c:453
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
static void fatal_error(const char *fmt,...) pg_attribute_printf(1
Definition: pg_waldump.c:79
static void identify_target_directory(XLogDumpPrivate *private, char *directory, char *fname)
Definition: pg_waldump.c:256
RmgrId xl_rmid
Definition: xlogrecord.h:47
TransactionId filter_by_xid
Definition: pg_waldump.c:53
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
bool bkp_details
Definition: pg_waldump.c:44
static int fd(const char *x, int i)
Definition: preproc-init.c:105
XLogRecord * XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
Definition: xlogreader.c:193
#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes)
bool filter_by_xid_enabled
Definition: pg_waldump.c:54
void pg_usleep(long microsec)
Definition: signal.c:53
#define required_argument
Definition: getopt_long.h:25
int optind
Definition: getopt.c:51
const RmgrDescData RmgrDescTable[RM_MAX_ID+1]
Definition: rmgrdesc.c:38
#define XLogFromFileName(fname, tli, logSegNo, wal_segsz_bytes)
static void XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogReaderState *record)
Definition: pg_waldump.c:492
static int XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff, TimeLineID *curFileTLI)
Definition: pg_waldump.c:434
uint64 XLogSegNo
Definition: xlogdefs.h:34
static void XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record)
Definition: pg_waldump.c:530
XLogRecPtr ReadRecPtr
Definition: xlogreader.h:119
#define XLogSegNoOffsetToRecPtr(segno, offset, dest, wal_segsz_bytes)
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define InvalidTransactionId
Definition: transam.h:31
static void split_path(const char *path, char **dir, char **fname)
Definition: pg_waldump.c:127
unsigned int uint32
Definition: c.h:325
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
void XLogReaderFree(XLogReaderState *state)
Definition: xlogreader.c:125
#define RM_MAX_ID
Definition: rmgr.h:33
XLogReaderState * XLogReaderAllocate(int wal_segment_size, XLogPageReadCB pagereadfunc, void *private_data)
Definition: xlogreader.c:65
#define no_argument
Definition: getopt_long.h:24
#define ngettext(s, p, n)
Definition: c.h:1022
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1054
static int WalSegSz
Definition: pg_waldump.c:30
#define XLogSegmentOffset(xlogptr, wal_segsz_bytes)
uint64 XLogRecPtr
Definition: xlogdefs.h:21
static const char * directory
Definition: zic.c:575
static int open_file_in_directory(const char *directory, const char *fname)
Definition: pg_waldump.c:155
#define optional_argument
Definition: getopt_long.h:26
static bool verify_directory(const char *directory)
Definition: pg_waldump.c:110
TransactionId xl_xid
Definition: xlogrecord.h:44
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:550
static const char * progname
Definition: pg_waldump.c:28
char * optarg
Definition: getopt.c:53
int i
const char * strerror(int errnum)
Definition: strerror.c:19
int stop_after_records
Definition: pg_waldump.c:45
#define EXIT_FAILURE
Definition: settings.h:152
static void print_rmgr_list(void)
Definition: pg_waldump.c:95
bool stats_per_record
Definition: pg_waldump.c:49
#define close(a)
Definition: win32.h:12
#define _(x)
Definition: elog.c:84
static XLogRecPtr startptr
Definition: basebackup.c:106

◆ open_file_in_directory()

static int open_file_in_directory ( const char *  directory,
const char *  fname 
)
static

Definition at line 155 of file pg_waldump.c.

References Assert, fatal_error(), fd(), MAXPGPATH, PG_BINARY, snprintf(), and strerror().

Referenced by main(), search_directory(), and XLogDumpXLogRead().

156 {
157  int fd = -1;
158  char fpath[MAXPGPATH];
159 
160  Assert(directory != NULL);
161 
162  snprintf(fpath, MAXPGPATH, "%s/%s", directory, fname);
163  fd = open(fpath, O_RDONLY | PG_BINARY, 0);
164 
165  if (fd < 0 && errno != ENOENT)
166  fatal_error("could not open file \"%s\": %s",
167  fname, strerror(errno));
168  return fd;
169 }
static void fatal_error(const char *fmt,...) pg_attribute_printf(1
Definition: pg_waldump.c:79
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1080
#define MAXPGPATH
#define Assert(condition)
Definition: c.h:699
static const char * directory
Definition: zic.c:575
const char * strerror(int errnum)
Definition: strerror.c:19

◆ print_rmgr_list()

static void print_rmgr_list ( void  )
static

Definition at line 95 of file pg_waldump.c.

References i, RM_MAX_ID, and RmgrDescTable.

Referenced by main().

96 {
97  int i;
98 
99  for (i = 0; i <= RM_MAX_ID; i++)
100  {
101  printf("%s\n", RmgrDescTable[i].rm_name);
102  }
103 }
const RmgrDescData RmgrDescTable[RM_MAX_ID+1]
Definition: rmgrdesc.c:38
#define RM_MAX_ID
Definition: rmgr.h:33
int i

◆ search_directory()

static bool search_directory ( const char *  directory,
const char *  fname 
)
static

Definition at line 178 of file pg_waldump.c.

References buf, close, closedir(), dirent::d_name, fatal_error(), fd(), IsValidWalSegSize, IsXLogFileName, ngettext, open_file_in_directory(), opendir(), read, readdir(), strerror(), WalSegSz, and XLogLongPageHeaderData::xlp_seg_size.

Referenced by identify_target_directory().

179 {
180  int fd = -1;
181  DIR *xldir;
182 
183  /* open file if valid filename is provided */
184  if (fname != NULL)
185  fd = open_file_in_directory(directory, fname);
186 
187  /*
188  * A valid file name is not passed, so search the complete directory. If
189  * we find any file whose name is a valid WAL file name then try to open
190  * it. If we cannot open it, bail out.
191  */
192  else if ((xldir = opendir(directory)) != NULL)
193  {
194  struct dirent *xlde;
195 
196  while ((xlde = readdir(xldir)) != NULL)
197  {
198  if (IsXLogFileName(xlde->d_name))
199  {
201  fname = xlde->d_name;
202  break;
203  }
204  }
205 
206  closedir(xldir);
207  }
208 
209  /* set WalSegSz if file is successfully opened */
210  if (fd >= 0)
211  {
212  char buf[XLOG_BLCKSZ];
213 
214  if (read(fd, buf, XLOG_BLCKSZ) == XLOG_BLCKSZ)
215  {
216  XLogLongPageHeader longhdr = (XLogLongPageHeader) buf;
217 
218  WalSegSz = longhdr->xlp_seg_size;
219 
221  fatal_error(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",
222  "WAL segment size must be a power of two between 1 MB and 1 GB, but the WAL file \"%s\" header specifies %d bytes",
223  WalSegSz),
224  fname, WalSegSz);
225  }
226  else
227  {
228  if (errno != 0)
229  fatal_error("could not read file \"%s\": %s",
230  fname, strerror(errno));
231  else
232  fatal_error("not enough data in file \"%s\"", fname);
233  }
234  close(fd);
235  return true;
236  }
237 
238  return false;
239 }
#define IsValidWalSegSize(size)
Definition: xlog_internal.h:97
static void fatal_error(const char *fmt,...) pg_attribute_printf(1
Definition: pg_waldump.c:79
int closedir(DIR *)
Definition: dirent.c:111
Definition: dirent.h:9
static int fd(const char *x, int i)
Definition: preproc-init.c:105
XLogLongPageHeaderData * XLogLongPageHeader
Definition: xlog_internal.h:74
Definition: dirent.c:25
#define IsXLogFileName(fname)
DIR * opendir(const char *)
Definition: dirent.c:33
static char * buf
Definition: pg_test_fsync.c:67
#define ngettext(s, p, n)
Definition: c.h:1022
static int WalSegSz
Definition: pg_waldump.c:30
static const char * directory
Definition: zic.c:575
static int open_file_in_directory(const char *directory, const char *fname)
Definition: pg_waldump.c:155
struct dirent * readdir(DIR *)
Definition: dirent.c:77
const char * strerror(int errnum)
Definition: strerror.c:19
char d_name[MAX_PATH]
Definition: dirent.h:14
#define close(a)
Definition: win32.h:12
#define read(a, b, c)
Definition: win32.h:13

◆ split_path()

static void split_path ( const char *  path,
char **  dir,
char **  fname 
)
static

Definition at line 127 of file pg_waldump.c.

References pg_strdup().

Referenced by main().

128 {
129  char *sep;
130 
131  /* split filepath into directory & filename */
132  sep = strrchr(path, '/');
133 
134  /* directory path */
135  if (sep != NULL)
136  {
137  *dir = pg_strdup(path);
138  (*dir)[(sep - path) + 1] = '\0'; /* no strndup */
139  *fname = pg_strdup(sep + 1);
140  }
141  /* local directory */
142  else
143  {
144  *dir = NULL;
145  *fname = pg_strdup(path);
146  }
147 }
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85

◆ usage()

static void usage ( void  )
static

Definition at line 794 of file pg_waldump.c.

References _, and progname.

Referenced by main().

795 {
796  printf(_("%s decodes and displays PostgreSQL write-ahead logs for debugging.\n\n"),
797  progname);
798  printf(_("Usage:\n"));
799  printf(_(" %s [OPTION]... [STARTSEG [ENDSEG]]\n"), progname);
800  printf(_("\nOptions:\n"));
801  printf(_(" -b, --bkp-details output detailed information about backup blocks\n"));
802  printf(_(" -e, --end=RECPTR stop reading at WAL location RECPTR\n"));
803  printf(_(" -f, --follow keep retrying after reaching end of WAL\n"));
804  printf(_(" -n, --limit=N number of records to display\n"));
805  printf(_(" -p, --path=PATH directory in which to find log segment files or a\n"
806  " directory with a ./pg_wal that contains such files\n"
807  " (default: current directory, ./pg_wal, $PGDATA/pg_wal)\n"));
808  printf(_(" -r, --rmgr=RMGR only show records generated by resource manager RMGR;\n"
809  " use --rmgr=list to list valid resource manager names\n"));
810  printf(_(" -s, --start=RECPTR start reading at WAL location RECPTR\n"));
811  printf(_(" -t, --timeline=TLI timeline from which to read log records\n"
812  " (default: 1 or the value used in STARTSEG)\n"));
813  printf(_(" -V, --version output version information, then exit\n"));
814  printf(_(" -x, --xid=XID only show records with transaction ID XID\n"));
815  printf(_(" -z, --stats[=record] show statistics instead of records\n"
816  " (optionally, show per-record statistics)\n"));
817  printf(_(" -?, --help show this help, then exit\n"));
818 }
static const char * progname
Definition: pg_waldump.c:28
#define _(x)
Definition: elog.c:84

◆ verify_directory()

static bool verify_directory ( const char *  directory)
static

Definition at line 110 of file pg_waldump.c.

References closedir(), and opendir().

Referenced by main().

111 {
112  DIR *dir = opendir(directory);
113 
114  if (dir == NULL)
115  return false;
116  closedir(dir);
117  return true;
118 }
int closedir(DIR *)
Definition: dirent.c:111
Definition: dirent.c:25
DIR * opendir(const char *)
Definition: dirent.c:33
static const char * directory
Definition: zic.c:575

◆ XLogDumpCountRecord()

static void XLogDumpCountRecord ( XLogDumpConfig config,
XLogDumpStats stats,
XLogReaderState record 
)
static

Definition at line 492 of file pg_waldump.c.

References Stats::count, XLogDumpStats::count, Stats::fpi_len, Stats::rec_len, XLogDumpStats::record_stats, XLogDumpStats::rmgr_stats, XLogDumpRecordLen(), XLogRecGetInfo, and XLogRecGetRmid.

Referenced by main().

494 {
495  RmgrId rmid;
496  uint8 recid;
497  uint32 rec_len;
498  uint32 fpi_len;
499 
500  stats->count++;
501 
502  rmid = XLogRecGetRmid(record);
503 
504  XLogDumpRecordLen(record, &rec_len, &fpi_len);
505 
506  /* Update per-rmgr statistics */
507 
508  stats->rmgr_stats[rmid].count++;
509  stats->rmgr_stats[rmid].rec_len += rec_len;
510  stats->rmgr_stats[rmid].fpi_len += fpi_len;
511 
512  /*
513  * Update per-record statistics, where the record is identified by a
514  * combination of the RmgrId and the four bits of the xl_info field that
515  * are the rmgr's domain (resulting in sixteen possible entries per
516  * RmgrId).
517  */
518 
519  recid = XLogRecGetInfo(record) >> 4;
520 
521  stats->record_stats[rmid][recid].count++;
522  stats->record_stats[rmid][recid].rec_len += rec_len;
523  stats->record_stats[rmid][recid].fpi_len += fpi_len;
524 }
uint64 count
Definition: pg_waldump.c:59
uint64 count
Definition: pg_waldump.c:68
unsigned char uint8
Definition: c.h:323
Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES]
Definition: pg_waldump.c:70
Stats rmgr_stats[RM_NEXT_ID]
Definition: pg_waldump.c:69
unsigned int uint32
Definition: c.h:325
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:226
uint8 RmgrId
Definition: rmgr.h:11
uint64 fpi_len
Definition: pg_waldump.c:61
uint64 rec_len
Definition: pg_waldump.c:60
#define XLogRecGetRmid(decoder)
Definition: xlogreader.h:227
static void XLogDumpRecordLen(XLogReaderState *record, uint32 *rec_len, uint32 *fpi_len)
Definition: pg_waldump.c:463

◆ XLogDumpDisplayRecord()

static void XLogDumpDisplayRecord ( XLogDumpConfig config,
XLogReaderState record 
)
static

Definition at line 530 of file pg_waldump.c.

References DecodedBkpBlock::bimg_info, DecodedBkpBlock::bimg_len, XLogDumpConfig::bkp_details, BKPIMAGE_IS_COMPRESSED, XLogReaderState::blocks, RelFileNode::dbNode, forkNames, DecodedBkpBlock::hole_length, DecodedBkpBlock::hole_offset, MAIN_FORKNUM, XLogReaderState::max_block_id, psprintf(), XLogReaderState::ReadRecPtr, RelFileNode::relNode, RmgrDescData::rm_desc, RmgrDescData::rm_identify, RmgrDescData::rm_name, RmgrDescTable, RelFileNode::spcNode, XLogDumpRecordLen(), XLogRecBlockImageApply, XLogRecGetBlockTag(), XLogRecGetInfo, XLogRecGetPrev, XLogRecGetRmid, XLogRecGetTotalLen, XLogRecGetXid, XLogRecHasBlockImage, XLogRecHasBlockRef, and XLR_INFO_MASK.

Referenced by main().

531 {
532  const char *id;
533  const RmgrDescData *desc = &RmgrDescTable[XLogRecGetRmid(record)];
534  uint32 rec_len;
535  uint32 fpi_len;
536  RelFileNode rnode;
537  ForkNumber forknum;
538  BlockNumber blk;
539  int block_id;
540  uint8 info = XLogRecGetInfo(record);
541  XLogRecPtr xl_prev = XLogRecGetPrev(record);
542 
543  XLogDumpRecordLen(record, &rec_len, &fpi_len);
544 
545  id = desc->rm_identify(info);
546  if (id == NULL)
547  id = psprintf("UNKNOWN (%x)", info & ~XLR_INFO_MASK);
548 
549  printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
550  desc->rm_name,
551  rec_len, XLogRecGetTotalLen(record),
552  XLogRecGetXid(record),
553  (uint32) (record->ReadRecPtr >> 32), (uint32) record->ReadRecPtr,
554  (uint32) (xl_prev >> 32), (uint32) xl_prev);
555  printf("desc: %s ", id);
556 
557  /* the desc routine will printf the description directly to stdout */
558  desc->rm_desc(NULL, record);
559 
560  if (!config->bkp_details)
561  {
562  /* print block references (short format) */
563  for (block_id = 0; block_id <= record->max_block_id; block_id++)
564  {
565  if (!XLogRecHasBlockRef(record, block_id))
566  continue;
567 
568  XLogRecGetBlockTag(record, block_id, &rnode, &forknum, &blk);
569  if (forknum != MAIN_FORKNUM)
570  printf(", blkref #%u: rel %u/%u/%u fork %s blk %u",
571  block_id,
572  rnode.spcNode, rnode.dbNode, rnode.relNode,
573  forkNames[forknum],
574  blk);
575  else
576  printf(", blkref #%u: rel %u/%u/%u blk %u",
577  block_id,
578  rnode.spcNode, rnode.dbNode, rnode.relNode,
579  blk);
580  if (XLogRecHasBlockImage(record, block_id))
581  {
582  if (XLogRecBlockImageApply(record, block_id))
583  printf(" FPW");
584  else
585  printf(" FPW for WAL verification");
586  }
587  }
588  putchar('\n');
589  }
590  else
591  {
592  /* print block references (detailed format) */
593  putchar('\n');
594  for (block_id = 0; block_id <= record->max_block_id; block_id++)
595  {
596  if (!XLogRecHasBlockRef(record, block_id))
597  continue;
598 
599  XLogRecGetBlockTag(record, block_id, &rnode, &forknum, &blk);
600  printf("\tblkref #%u: rel %u/%u/%u fork %s blk %u",
601  block_id,
602  rnode.spcNode, rnode.dbNode, rnode.relNode,
603  forkNames[forknum],
604  blk);
605  if (XLogRecHasBlockImage(record, block_id))
606  {
607  if (record->blocks[block_id].bimg_info &
609  {
610  printf(" (FPW%s); hole: offset: %u, length: %u, "
611  "compression saved: %u\n",
612  XLogRecBlockImageApply(record, block_id) ?
613  "" : " for WAL verification",
614  record->blocks[block_id].hole_offset,
615  record->blocks[block_id].hole_length,
616  BLCKSZ -
617  record->blocks[block_id].hole_length -
618  record->blocks[block_id].bimg_len);
619  }
620  else
621  {
622  printf(" (FPW%s); hole: offset: %u, length: %u\n",
623  XLogRecBlockImageApply(record, block_id) ?
624  "" : " for WAL verification",
625  record->blocks[block_id].hole_offset,
626  record->blocks[block_id].hole_length);
627  }
628  }
629  putchar('\n');
630  }
631  }
632 }
#define XLogRecHasBlockImage(decoder, block_id)
Definition: xlogreader.h:235
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
uint16 hole_offset
Definition: xlogreader.h:57
unsigned char uint8
Definition: c.h:323
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:233
uint32 BlockNumber
Definition: block.h:31
bool bkp_details
Definition: pg_waldump.c:44
uint16 bimg_len
Definition: xlogreader.h:59
#define XLogRecGetTotalLen(decoder)
Definition: xlogreader.h:224
uint16 hole_length
Definition: xlogreader.h:58
const RmgrDescData RmgrDescTable[RM_MAX_ID+1]
Definition: rmgrdesc.c:38
#define XLogRecGetPrev(decoder)
Definition: xlogreader.h:225
XLogRecPtr ReadRecPtr
Definition: xlogreader.h:119
unsigned int uint32
Definition: c.h:325
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:226
ForkNumber
Definition: relpath.h:40
const char * rm_name
Definition: rmgrdesc.h:15
bool XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileNode *rnode, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1335
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:228
#define BKPIMAGE_IS_COMPRESSED
Definition: xlogrecord.h:148
const char *(* rm_identify)(uint8 info)
Definition: rmgrdesc.h:17
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
void(* rm_desc)(StringInfo buf, XLogReaderState *record)
Definition: rmgrdesc.h:16
#define XLogRecBlockImageApply(decoder, block_id)
Definition: xlogreader.h:237
const char *const forkNames[]
Definition: relpath.c:33
DecodedBkpBlock blocks[XLR_MAX_BLOCK_ID+1]
Definition: xlogreader.h:139
#define XLogRecGetRmid(decoder)
Definition: xlogreader.h:227
static void XLogDumpRecordLen(XLogReaderState *record, uint32 *rec_len, uint32 *fpi_len)
Definition: pg_waldump.c:463

◆ XLogDumpDisplayStats()

static void XLogDumpDisplayStats ( XLogDumpConfig config,
XLogDumpStats stats 
)
static

Definition at line 679 of file pg_waldump.c.

References Stats::count, XLogDumpStats::count, Stats::fpi_len, MAX_XLINFO_TYPES, psprintf(), Stats::rec_len, XLogDumpStats::record_stats, RmgrDescData::rm_identify, RmgrDescData::rm_name, RM_NEXT_ID, XLogDumpStats::rmgr_stats, RmgrDescTable, XLogDumpConfig::stats_per_record, and XLogDumpStatsRow().

Referenced by main().

680 {
681  int ri,
682  rj;
683  uint64 total_count = 0;
684  uint64 total_rec_len = 0;
685  uint64 total_fpi_len = 0;
686  uint64 total_len = 0;
687  double rec_len_pct,
688  fpi_len_pct;
689 
690  /* ---
691  * Make a first pass to calculate column totals:
692  * count(*),
693  * sum(xl_len+SizeOfXLogRecord),
694  * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and
695  * sum(xl_tot_len).
696  * These are used to calculate percentages for each record type.
697  * ---
698  */
699 
700  for (ri = 0; ri < RM_NEXT_ID; ri++)
701  {
702  total_count += stats->rmgr_stats[ri].count;
703  total_rec_len += stats->rmgr_stats[ri].rec_len;
704  total_fpi_len += stats->rmgr_stats[ri].fpi_len;
705  }
706  total_len = total_rec_len + total_fpi_len;
707 
708  /*
709  * 27 is strlen("Transaction/COMMIT_PREPARED"), 20 is strlen(2^64), 8 is
710  * strlen("(100.00%)")
711  */
712 
713  printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
714  "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
715  "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
716  "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
717 
718  for (ri = 0; ri < RM_NEXT_ID; ri++)
719  {
720  uint64 count,
721  rec_len,
722  fpi_len,
723  tot_len;
724  const RmgrDescData *desc = &RmgrDescTable[ri];
725 
726  if (!config->stats_per_record)
727  {
728  count = stats->rmgr_stats[ri].count;
729  rec_len = stats->rmgr_stats[ri].rec_len;
730  fpi_len = stats->rmgr_stats[ri].fpi_len;
731  tot_len = rec_len + fpi_len;
732 
734  count, total_count, rec_len, total_rec_len,
735  fpi_len, total_fpi_len, tot_len, total_len);
736  }
737  else
738  {
739  for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
740  {
741  const char *id;
742 
743  count = stats->record_stats[ri][rj].count;
744  rec_len = stats->record_stats[ri][rj].rec_len;
745  fpi_len = stats->record_stats[ri][rj].fpi_len;
746  tot_len = rec_len + fpi_len;
747 
748  /* Skip undefined combinations and ones that didn't occur */
749  if (count == 0)
750  continue;
751 
752  /* the upper four bits in xl_info are the rmgr's */
753  id = desc->rm_identify(rj << 4);
754  if (id == NULL)
755  id = psprintf("UNKNOWN (%x)", rj << 4);
756 
757  XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
758  count, total_count, rec_len, total_rec_len,
759  fpi_len, total_fpi_len, tot_len, total_len);
760  }
761  }
762  }
763 
764  printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
765  "", "--------", "", "--------", "", "--------", "", "--------");
766 
767  /*
768  * The percentages in earlier rows were calculated against the column
769  * total, but the ones that follow are against the row total. Note that
770  * these are displayed with a % symbol to differentiate them from the
771  * earlier ones, and are thus up to 9 characters long.
772  */
773 
774  rec_len_pct = 0;
775  if (total_len != 0)
776  rec_len_pct = 100 * (double) total_rec_len / total_len;
777 
778  fpi_len_pct = 0;
779  if (total_len != 0)
780  fpi_len_pct = 100 * (double) total_fpi_len / total_len;
781 
782  printf("%-27s "
783  "%20" INT64_MODIFIER "u %-9s"
784  "%20" INT64_MODIFIER "u %-9s"
785  "%20" INT64_MODIFIER "u %-9s"
786  "%20" INT64_MODIFIER "u %-6s\n",
787  "Total", stats->count, "",
788  total_rec_len, psprintf("[%.02f%%]", rec_len_pct),
789  total_fpi_len, psprintf("[%.02f%%]", fpi_len_pct),
790  total_len, "[100%]");
791 }
uint64 count
Definition: pg_waldump.c:59
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
uint64 count
Definition: pg_waldump.c:68
Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES]
Definition: pg_waldump.c:70
Stats rmgr_stats[RM_NEXT_ID]
Definition: pg_waldump.c:69
const RmgrDescData RmgrDescTable[RM_MAX_ID+1]
Definition: rmgrdesc.c:38
const char * rm_name
Definition: rmgrdesc.h:15
const char *(* rm_identify)(uint8 info)
Definition: rmgrdesc.h:17
#define MAX_XLINFO_TYPES
Definition: pg_waldump.c:64
uint64 fpi_len
Definition: pg_waldump.c:61
uint64 rec_len
Definition: pg_waldump.c:60
static void XLogDumpStatsRow(const char *name, uint64 n, uint64 total_count, uint64 rec_len, uint64 total_rec_len, uint64 fpi_len, uint64 total_fpi_len, uint64 tot_len, uint64 total_len)
Definition: pg_waldump.c:638
bool stats_per_record
Definition: pg_waldump.c:49

◆ XLogDumpReadPage()

static int XLogDumpReadPage ( XLogReaderState state,
XLogRecPtr  targetPagePtr,
int  reqLen,
XLogRecPtr  targetPtr,
char *  readBuff,
TimeLineID curFileTLI 
)
static

Definition at line 434 of file pg_waldump.c.

References XLogDumpPrivate::endptr, InvalidXLogRecPtr, XLogReaderState::private_data, and XLogDumpXLogRead().

Referenced by main().

436 {
437  XLogDumpPrivate *private = state->private_data;
438  int count = XLOG_BLCKSZ;
439 
440  if (private->endptr != InvalidXLogRecPtr)
441  {
442  if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
443  count = XLOG_BLCKSZ;
444  else if (targetPagePtr + reqLen <= private->endptr)
445  count = private->endptr - targetPagePtr;
446  else
447  {
448  private->endptr_reached = true;
449  return -1;
450  }
451  }
452 
453  XLogDumpXLogRead(private->inpath, private->timeline, targetPagePtr,
454  readBuff, count);
455 
456  return count;
457 }
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
void * private_data
Definition: xlogreader.h:113
static void XLogDumpXLogRead(const char *directory, TimeLineID timeline_id, XLogRecPtr startptr, char *buf, Size count)
Definition: pg_waldump.c:320

◆ XLogDumpRecordLen()

static void XLogDumpRecordLen ( XLogReaderState record,
uint32 rec_len,
uint32 fpi_len 
)
static

Definition at line 463 of file pg_waldump.c.

References DecodedBkpBlock::bimg_len, XLogReaderState::blocks, XLogReaderState::max_block_id, XLogRecGetTotalLen, and XLogRecHasBlockImage.

Referenced by XLogDumpCountRecord(), and XLogDumpDisplayRecord().

464 {
465  int block_id;
466 
467  /*
468  * Calculate the amount of FPI data in the record.
469  *
470  * XXX: We peek into xlogreader's private decoded backup blocks for the
471  * bimg_len indicating the length of FPI data. It doesn't seem worth it to
472  * add an accessor macro for this.
473  */
474  *fpi_len = 0;
475  for (block_id = 0; block_id <= record->max_block_id; block_id++)
476  {
477  if (XLogRecHasBlockImage(record, block_id))
478  *fpi_len += record->blocks[block_id].bimg_len;
479  }
480 
481  /*
482  * Calculate the length of the record as the total length - the length of
483  * all the block images.
484  */
485  *rec_len = XLogRecGetTotalLen(record) - *fpi_len;
486 }
#define XLogRecHasBlockImage(decoder, block_id)
Definition: xlogreader.h:235
uint16 bimg_len
Definition: xlogreader.h:59
#define XLogRecGetTotalLen(decoder)
Definition: xlogreader.h:224
DecodedBkpBlock blocks[XLR_MAX_BLOCK_ID+1]
Definition: xlogreader.h:139

◆ XLogDumpStatsRow()

static void XLogDumpStatsRow ( const char *  name,
uint64  n,
uint64  total_count,
uint64  rec_len,
uint64  total_rec_len,
uint64  fpi_len,
uint64  total_fpi_len,
uint64  tot_len,
uint64  total_len 
)
static

Definition at line 638 of file pg_waldump.c.

Referenced by XLogDumpDisplayStats().

643 {
644  double n_pct,
645  rec_len_pct,
646  fpi_len_pct,
647  tot_len_pct;
648 
649  n_pct = 0;
650  if (total_count != 0)
651  n_pct = 100 * (double) n / total_count;
652 
653  rec_len_pct = 0;
654  if (total_rec_len != 0)
655  rec_len_pct = 100 * (double) rec_len / total_rec_len;
656 
657  fpi_len_pct = 0;
658  if (total_fpi_len != 0)
659  fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
660 
661  tot_len_pct = 0;
662  if (total_len != 0)
663  tot_len_pct = 100 * (double) tot_len / total_len;
664 
665  printf("%-27s "
666  "%20" INT64_MODIFIER "u (%6.02f) "
667  "%20" INT64_MODIFIER "u (%6.02f) "
668  "%20" INT64_MODIFIER "u (%6.02f) "
669  "%20" INT64_MODIFIER "u (%6.02f)\n",
670  name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
671  tot_len, tot_len_pct);
672 }
const char * name
Definition: encode.c:521

◆ XLogDumpXLogRead()

static void XLogDumpXLogRead ( const char *  directory,
TimeLineID  timeline_id,
XLogRecPtr  startptr,
char *  buf,
Size  count 
)
static

Definition at line 320 of file pg_waldump.c.

References buf, close, fatal_error(), MAXFNAMELEN, MAXPGPATH, open_file_in_directory(), pg_usleep(), read, sendFile, sendOff, sendSegNo, XLogDumpPrivate::startptr, strerror(), WalSegSz, XLByteInSeg, XLByteToSeg, XLogFileName, and XLogSegmentOffset.

Referenced by XLogDumpReadPage().

322 {
323  char *p;
324  XLogRecPtr recptr;
325  Size nbytes;
326 
327  static int sendFile = -1;
328  static XLogSegNo sendSegNo = 0;
329  static uint32 sendOff = 0;
330 
331  p = buf;
332  recptr = startptr;
333  nbytes = count;
334 
335  while (nbytes > 0)
336  {
337  uint32 startoff;
338  int segbytes;
339  int readbytes;
340 
341  startoff = XLogSegmentOffset(recptr, WalSegSz);
342 
343  if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo, WalSegSz))
344  {
345  char fname[MAXFNAMELEN];
346  int tries;
347 
348  /* Switch to another logfile segment */
349  if (sendFile >= 0)
350  close(sendFile);
351 
352  XLByteToSeg(recptr, sendSegNo, WalSegSz);
353 
354  XLogFileName(fname, timeline_id, sendSegNo, WalSegSz);
355 
356  /*
357  * In follow mode there is a short period of time after the server
358  * has written the end of the previous file before the new file is
359  * available. So we loop for 5 seconds looking for the file to
360  * appear before giving up.
361  */
362  for (tries = 0; tries < 10; tries++)
363  {
364  sendFile = open_file_in_directory(directory, fname);
365  if (sendFile >= 0)
366  break;
367  if (errno == ENOENT)
368  {
369  int save_errno = errno;
370 
371  /* File not there yet, try again */
372  pg_usleep(500 * 1000);
373 
374  errno = save_errno;
375  continue;
376  }
377  /* Any other error, fall through and fail */
378  break;
379  }
380 
381  if (sendFile < 0)
382  fatal_error("could not find file \"%s\": %s",
383  fname, strerror(errno));
384  sendOff = 0;
385  }
386 
387  /* Need to seek in the file? */
388  if (sendOff != startoff)
389  {
390  if (lseek(sendFile, (off_t) startoff, SEEK_SET) < 0)
391  {
392  int err = errno;
393  char fname[MAXPGPATH];
394 
395  XLogFileName(fname, timeline_id, sendSegNo, WalSegSz);
396 
397  fatal_error("could not seek in log file %s to offset %u: %s",
398  fname, startoff, strerror(err));
399  }
400  sendOff = startoff;
401  }
402 
403  /* How many bytes are within this segment? */
404  if (nbytes > (WalSegSz - startoff))
405  segbytes = WalSegSz - startoff;
406  else
407  segbytes = nbytes;
408 
409  readbytes = read(sendFile, p, segbytes);
410  if (readbytes <= 0)
411  {
412  int err = errno;
413  char fname[MAXPGPATH];
414 
415  XLogFileName(fname, timeline_id, sendSegNo, WalSegSz);
416 
417  fatal_error("could not read from log file %s, offset %u, length %d: %s",
418  fname, sendOff, segbytes, strerror(err));
419  }
420 
421  /* Update state for read */
422  recptr += readbytes;
423 
424  sendOff += readbytes;
425  nbytes -= readbytes;
426  p += readbytes;
427  }
428 }
static void fatal_error(const char *fmt,...) pg_attribute_printf(1
Definition: pg_waldump.c:79
static int sendFile
Definition: walsender.c:136
#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes)
void pg_usleep(long microsec)
Definition: signal.c:53
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:67
uint64 XLogSegNo
Definition: xlogdefs.h:34
unsigned int uint32
Definition: c.h:325
#define MAXFNAMELEN
static int WalSegSz
Definition: pg_waldump.c:30
#define XLogSegmentOffset(xlogptr, wal_segsz_bytes)
uint64 XLogRecPtr
Definition: xlogdefs.h:21
size_t Size
Definition: c.h:433
#define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes)
static const char * directory
Definition: zic.c:575
static int open_file_in_directory(const char *directory, const char *fname)
Definition: pg_waldump.c:155
static XLogSegNo sendSegNo
Definition: walsender.c:137
const char * strerror(int errnum)
Definition: strerror.c:19
static uint32 sendOff
Definition: walsender.c:138
#define close(a)
Definition: win32.h:12
#define read(a, b, c)
Definition: win32.h:13
static XLogRecPtr startptr
Definition: basebackup.c:106
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes)

Variable Documentation

◆ progname

const char* progname
static

Definition at line 28 of file pg_waldump.c.

Referenced by fatal_error(), main(), and usage().

◆ WalSegSz

int WalSegSz
static

Definition at line 30 of file pg_waldump.c.

Referenced by main(), search_directory(), and XLogDumpXLogRead().