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

Go to the source code of this file.

Data Structures

struct  XLogDumpPrivate
 
struct  XLogDumpConfig
 

Macros

#define FRONTEND   1
 

Typedefs

typedef struct XLogDumpPrivate XLogDumpPrivate
 
typedef struct XLogDumpConfig XLogDumpConfig
 

Functions

static void sigint_handler (SIGNAL_ARGS)
 
static void print_rmgr_list (void)
 
static bool verify_directory (const char *directory)
 
static void create_fullpage_directory (char *path)
 
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 char * identify_target_directory (char *directory, char *fname)
 
static void WALDumpOpenSegment (XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
 
static void WALDumpCloseSegment (XLogReaderState *state)
 
static int WALDumpReadPage (XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff)
 
static bool XLogRecordMatchesRelationBlock (XLogReaderState *record, RelFileLocator matchRlocator, BlockNumber matchBlock, ForkNumber matchFork)
 
static bool XLogRecordHasFPW (XLogReaderState *record)
 
static void XLogRecordSaveFPWs (XLogReaderState *record, const char *savepath)
 
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, XLogStats *stats)
 
static void usage (void)
 
int main (int argc, char **argv)
 

Variables

static const char * progname
 
static int WalSegSz
 
static volatile sig_atomic_t time_to_stop = false
 
static const RelFileLocator emptyRelFileLocator = {0, 0, 0}
 

Macro Definition Documentation

◆ FRONTEND

#define FRONTEND   1

Definition at line 12 of file pg_waldump.c.

Typedef Documentation

◆ XLogDumpConfig

◆ XLogDumpPrivate

Function Documentation

◆ create_fullpage_directory()

static void create_fullpage_directory ( char *  path)
static

Definition at line 127 of file pg_waldump.c.

128 {
129  int ret;
130 
131  switch ((ret = pg_check_dir(path)))
132  {
133  case 0:
134  /* Does not exist, so create it */
135  if (pg_mkdir_p(path, pg_dir_create_mode) < 0)
136  pg_fatal("could not create directory \"%s\": %m", path);
137  break;
138  case 1:
139  /* Present and empty, so do nothing */
140  break;
141  case 2:
142  case 3:
143  case 4:
144  /* Exists and not empty */
145  pg_fatal("directory \"%s\" exists but is not empty", path);
146  break;
147  default:
148  /* Trouble accessing directory */
149  pg_fatal("could not access directory \"%s\": %m", path);
150  }
151 }
int pg_dir_create_mode
Definition: file_perm.c:18
#define pg_fatal(...)
int pg_mkdir_p(char *path, int omode)
Definition: pgmkdirp.c:57
int pg_check_dir(const char *dir)
Definition: pgcheckdir.c:33

References pg_check_dir(), pg_dir_create_mode, pg_fatal, and pg_mkdir_p().

Referenced by main().

◆ identify_target_directory()

static char* identify_target_directory ( char *  directory,
char *  fname 
)
static

Definition at line 287 of file pg_waldump.c.

288 {
289  char fpath[MAXPGPATH];
290 
291  if (directory != NULL)
292  {
293  if (search_directory(directory, fname))
294  return pg_strdup(directory);
295 
296  /* directory / XLOGDIR */
297  snprintf(fpath, MAXPGPATH, "%s/%s", directory, XLOGDIR);
298  if (search_directory(fpath, fname))
299  return pg_strdup(fpath);
300  }
301  else
302  {
303  const char *datadir;
304 
305  /* current directory */
306  if (search_directory(".", fname))
307  return pg_strdup(".");
308  /* XLOGDIR */
309  if (search_directory(XLOGDIR, fname))
310  return pg_strdup(XLOGDIR);
311 
312  datadir = getenv("PGDATA");
313  /* $PGDATA / XLOGDIR */
314  if (datadir != NULL)
315  {
316  snprintf(fpath, MAXPGPATH, "%s/%s", datadir, XLOGDIR);
317  if (search_directory(fpath, fname))
318  return pg_strdup(fpath);
319  }
320  }
321 
322  /* could not locate WAL file */
323  if (fname)
324  pg_fatal("could not locate WAL file \"%s\"", fname);
325  else
326  pg_fatal("could not find any WAL file");
327 
328  return NULL; /* not reached */
329 }
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define MAXPGPATH
char * datadir
static bool search_directory(const char *directory, const char *fname)
Definition: pg_waldump.c:209
#define snprintf
Definition: port.h:238
#define XLOGDIR
static const char * directory
Definition: zic.c:634

References datadir, directory, MAXPGPATH, pg_fatal, pg_strdup(), search_directory(), snprintf, and XLOGDIR.

Referenced by main().

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 787 of file pg_waldump.c.

788 {
789  uint32 xlogid;
790  uint32 xrecoff;
791  XLogReaderState *xlogreader_state;
792  XLogDumpPrivate private;
793  XLogDumpConfig config;
794  XLogStats stats;
795  XLogRecord *record;
796  XLogRecPtr first_record;
797  char *waldir = NULL;
798  char *errormsg;
799 
800  static struct option long_options[] = {
801  {"bkp-details", no_argument, NULL, 'b'},
802  {"block", required_argument, NULL, 'B'},
803  {"end", required_argument, NULL, 'e'},
804  {"follow", no_argument, NULL, 'f'},
805  {"fork", required_argument, NULL, 'F'},
806  {"fullpage", no_argument, NULL, 'w'},
807  {"help", no_argument, NULL, '?'},
808  {"limit", required_argument, NULL, 'n'},
809  {"path", required_argument, NULL, 'p'},
810  {"quiet", no_argument, NULL, 'q'},
811  {"relation", required_argument, NULL, 'R'},
812  {"rmgr", required_argument, NULL, 'r'},
813  {"start", required_argument, NULL, 's'},
814  {"timeline", required_argument, NULL, 't'},
815  {"xid", required_argument, NULL, 'x'},
816  {"version", no_argument, NULL, 'V'},
817  {"stats", optional_argument, NULL, 'z'},
818  {"save-fullpage", required_argument, NULL, 1},
819  {NULL, 0, NULL, 0}
820  };
821 
822  int option;
823  int optindex = 0;
824 
825 #ifndef WIN32
826  pqsignal(SIGINT, sigint_handler);
827 #endif
828 
829  pg_logging_init(argv[0]);
830  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump"));
831  progname = get_progname(argv[0]);
832 
833  if (argc > 1)
834  {
835  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
836  {
837  usage();
838  exit(0);
839  }
840  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
841  {
842  puts("pg_waldump (PostgreSQL) " PG_VERSION);
843  exit(0);
844  }
845  }
846 
847  memset(&private, 0, sizeof(XLogDumpPrivate));
848  memset(&config, 0, sizeof(XLogDumpConfig));
849  memset(&stats, 0, sizeof(XLogStats));
850 
851  private.timeline = 1;
852  private.startptr = InvalidXLogRecPtr;
853  private.endptr = InvalidXLogRecPtr;
854  private.endptr_reached = false;
855 
856  config.quiet = false;
857  config.bkp_details = false;
858  config.stop_after_records = -1;
859  config.already_displayed_records = 0;
860  config.follow = false;
861  /* filter_by_rmgr array was zeroed by memset above */
862  config.filter_by_rmgr_enabled = false;
864  config.filter_by_xid_enabled = false;
865  config.filter_by_extended = false;
866  config.filter_by_relation_enabled = false;
867  config.filter_by_relation_block_enabled = false;
869  config.filter_by_fpw = false;
870  config.save_fullpage_path = NULL;
871  config.stats = false;
872  config.stats_per_record = false;
873 
874  stats.startptr = InvalidXLogRecPtr;
875  stats.endptr = InvalidXLogRecPtr;
876 
877  if (argc <= 1)
878  {
879  pg_log_error("no arguments specified");
880  goto bad_argument;
881  }
882 
883  while ((option = getopt_long(argc, argv, "bB:e:fF:n:p:qr:R:s:t:wx:z",
884  long_options, &optindex)) != -1)
885  {
886  switch (option)
887  {
888  case 'b':
889  config.bkp_details = true;
890  break;
891  case 'B':
892  if (sscanf(optarg, "%u", &config.filter_by_relation_block) != 1 ||
894  {
895  pg_log_error("invalid block number: \"%s\"", optarg);
896  goto bad_argument;
897  }
898  config.filter_by_relation_block_enabled = true;
899  config.filter_by_extended = true;
900  break;
901  case 'e':
902  if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2)
903  {
904  pg_log_error("invalid WAL location: \"%s\"",
905  optarg);
906  goto bad_argument;
907  }
908  private.endptr = (uint64) xlogid << 32 | xrecoff;
909  break;
910  case 'f':
911  config.follow = true;
912  break;
913  case 'F':
916  {
917  pg_log_error("invalid fork name: \"%s\"", optarg);
918  goto bad_argument;
919  }
920  config.filter_by_extended = true;
921  break;
922  case 'n':
923  if (sscanf(optarg, "%d", &config.stop_after_records) != 1)
924  {
925  pg_log_error("invalid value \"%s\" for option %s", optarg, "-n/--limit");
926  goto bad_argument;
927  }
928  break;
929  case 'p':
930  waldir = pg_strdup(optarg);
931  break;
932  case 'q':
933  config.quiet = true;
934  break;
935  case 'r':
936  {
937  int rmid;
938 
939  if (pg_strcasecmp(optarg, "list") == 0)
940  {
941  print_rmgr_list();
943  }
944 
945  /*
946  * First look for the generated name of a custom rmgr, of
947  * the form "custom###". We accept this form, because the
948  * custom rmgr module is not loaded, so there's no way to
949  * know the real name. This convention should be
950  * consistent with that in rmgrdesc.c.
951  */
952  if (sscanf(optarg, "custom%03d", &rmid) == 1)
953  {
954  if (!RmgrIdIsCustom(rmid))
955  {
956  pg_log_error("custom resource manager \"%s\" does not exist",
957  optarg);
958  goto bad_argument;
959  }
960  config.filter_by_rmgr[rmid] = true;
961  config.filter_by_rmgr_enabled = true;
962  }
963  else
964  {
965  /* then look for builtin rmgrs */
966  for (rmid = 0; rmid <= RM_MAX_BUILTIN_ID; rmid++)
967  {
968  if (pg_strcasecmp(optarg, GetRmgrDesc(rmid)->rm_name) == 0)
969  {
970  config.filter_by_rmgr[rmid] = true;
971  config.filter_by_rmgr_enabled = true;
972  break;
973  }
974  }
975  if (rmid > RM_MAX_BUILTIN_ID)
976  {
977  pg_log_error("resource manager \"%s\" does not exist",
978  optarg);
979  goto bad_argument;
980  }
981  }
982  }
983  break;
984  case 'R':
985  if (sscanf(optarg, "%u/%u/%u",
986  &config.filter_by_relation.spcOid,
987  &config.filter_by_relation.dbOid,
988  &config.filter_by_relation.relNumber) != 3 ||
991  {
992  pg_log_error("invalid relation specification: \"%s\"", optarg);
993  pg_log_error_detail("Expecting \"tablespace OID/database OID/relation filenode\".");
994  goto bad_argument;
995  }
996  config.filter_by_relation_enabled = true;
997  config.filter_by_extended = true;
998  break;
999  case 's':
1000  if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2)
1001  {
1002  pg_log_error("invalid WAL location: \"%s\"",
1003  optarg);
1004  goto bad_argument;
1005  }
1006  else
1007  private.startptr = (uint64) xlogid << 32 | xrecoff;
1008  break;
1009  case 't':
1010  if (sscanf(optarg, "%u", &private.timeline) != 1)
1011  {
1012  pg_log_error("invalid timeline specification: \"%s\"", optarg);
1013  goto bad_argument;
1014  }
1015  break;
1016  case 'w':
1017  config.filter_by_fpw = true;
1018  break;
1019  case 'x':
1020  if (sscanf(optarg, "%u", &config.filter_by_xid) != 1)
1021  {
1022  pg_log_error("invalid transaction ID specification: \"%s\"",
1023  optarg);
1024  goto bad_argument;
1025  }
1026  config.filter_by_xid_enabled = true;
1027  break;
1028  case 'z':
1029  config.stats = true;
1030  config.stats_per_record = false;
1031  if (optarg)
1032  {
1033  if (strcmp(optarg, "record") == 0)
1034  config.stats_per_record = true;
1035  else if (strcmp(optarg, "rmgr") != 0)
1036  {
1037  pg_log_error("unrecognized value for option %s: %s",
1038  "--stats", optarg);
1039  goto bad_argument;
1040  }
1041  }
1042  break;
1043  case 1:
1045  break;
1046  default:
1047  goto bad_argument;
1048  }
1049  }
1050 
1051  if (config.filter_by_relation_block_enabled &&
1053  {
1054  pg_log_error("option %s requires option %s to be specified",
1055  "-B/--block", "-R/--relation");
1056  goto bad_argument;
1057  }
1058 
1059  if ((optind + 2) < argc)
1060  {
1061  pg_log_error("too many command-line arguments (first is \"%s\")",
1062  argv[optind + 2]);
1063  goto bad_argument;
1064  }
1065 
1066  if (waldir != NULL)
1067  {
1068  /* validate path points to directory */
1069  if (!verify_directory(waldir))
1070  {
1071  pg_log_error("could not open directory \"%s\": %m", waldir);
1072  goto bad_argument;
1073  }
1074  }
1075 
1076  if (config.save_fullpage_path != NULL)
1078 
1079  /* parse files as start/end boundaries, extract path if not specified */
1080  if (optind < argc)
1081  {
1082  char *directory = NULL;
1083  char *fname = NULL;
1084  int fd;
1085  XLogSegNo segno;
1086 
1087  split_path(argv[optind], &directory, &fname);
1088 
1089  if (waldir == NULL && directory != NULL)
1090  {
1091  waldir = directory;
1092 
1093  if (!verify_directory(waldir))
1094  pg_fatal("could not open directory \"%s\": %m", waldir);
1095  }
1096 
1097  waldir = identify_target_directory(waldir, fname);
1098  fd = open_file_in_directory(waldir, fname);
1099  if (fd < 0)
1100  pg_fatal("could not open file \"%s\"", fname);
1101  close(fd);
1102 
1103  /* parse position from file */
1104  XLogFromFileName(fname, &private.timeline, &segno, WalSegSz);
1105 
1106  if (XLogRecPtrIsInvalid(private.startptr))
1107  XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr);
1108  else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
1109  {
1110  pg_log_error("start WAL location %X/%X is not inside file \"%s\"",
1111  LSN_FORMAT_ARGS(private.startptr),
1112  fname);
1113  goto bad_argument;
1114  }
1115 
1116  /* no second file specified, set end position */
1117  if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr))
1118  XLogSegNoOffsetToRecPtr(segno + 1, 0, WalSegSz, private.endptr);
1119 
1120  /* parse ENDSEG if passed */
1121  if (optind + 1 < argc)
1122  {
1123  XLogSegNo endsegno;
1124 
1125  /* ignore directory, already have that */
1126  split_path(argv[optind + 1], &directory, &fname);
1127 
1128  fd = open_file_in_directory(waldir, fname);
1129  if (fd < 0)
1130  pg_fatal("could not open file \"%s\"", fname);
1131  close(fd);
1132 
1133  /* parse position from file */
1134  XLogFromFileName(fname, &private.timeline, &endsegno, WalSegSz);
1135 
1136  if (endsegno < segno)
1137  pg_fatal("ENDSEG %s is before STARTSEG %s",
1138  argv[optind + 1], argv[optind]);
1139 
1140  if (XLogRecPtrIsInvalid(private.endptr))
1141  XLogSegNoOffsetToRecPtr(endsegno + 1, 0, WalSegSz,
1142  private.endptr);
1143 
1144  /* set segno to endsegno for check of --end */
1145  segno = endsegno;
1146  }
1147 
1148 
1149  if (!XLByteInSeg(private.endptr, segno, WalSegSz) &&
1150  private.endptr != (segno + 1) * WalSegSz)
1151  {
1152  pg_log_error("end WAL location %X/%X is not inside file \"%s\"",
1153  LSN_FORMAT_ARGS(private.endptr),
1154  argv[argc - 1]);
1155  goto bad_argument;
1156  }
1157  }
1158  else
1159  waldir = identify_target_directory(waldir, NULL);
1160 
1161  /* we don't know what to print */
1162  if (XLogRecPtrIsInvalid(private.startptr))
1163  {
1164  pg_log_error("no start WAL location given");
1165  goto bad_argument;
1166  }
1167 
1168  /* done with argument parsing, do the actual work */
1169 
1170  /* we have everything we need, start reading */
1171  xlogreader_state =
1172  XLogReaderAllocate(WalSegSz, waldir,
1173  XL_ROUTINE(.page_read = WALDumpReadPage,
1174  .segment_open = WALDumpOpenSegment,
1175  .segment_close = WALDumpCloseSegment),
1176  &private);
1177  if (!xlogreader_state)
1178  pg_fatal("out of memory while allocating a WAL reading processor");
1179 
1180  /* first find a valid recptr to start from */
1181  first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
1182 
1183  if (first_record == InvalidXLogRecPtr)
1184  pg_fatal("could not find a valid record after %X/%X",
1185  LSN_FORMAT_ARGS(private.startptr));
1186 
1187  /*
1188  * Display a message that we're skipping data if `from` wasn't a pointer
1189  * to the start of a record and also wasn't a pointer to the beginning of
1190  * a segment (e.g. we were used in file mode).
1191  */
1192  if (first_record != private.startptr &&
1193  XLogSegmentOffset(private.startptr, WalSegSz) != 0)
1194  printf(ngettext("first record is after %X/%X, at %X/%X, skipping over %u byte\n",
1195  "first record is after %X/%X, at %X/%X, skipping over %u bytes\n",
1196  (first_record - private.startptr)),
1197  LSN_FORMAT_ARGS(private.startptr),
1198  LSN_FORMAT_ARGS(first_record),
1199  (uint32) (first_record - private.startptr));
1200 
1201  if (config.stats == true && !config.quiet)
1202  stats.startptr = first_record;
1203 
1204  for (;;)
1205  {
1206  if (time_to_stop)
1207  {
1208  /* We've been Ctrl-C'ed, so leave */
1209  break;
1210  }
1211 
1212  /* try to read the next record */
1213  record = XLogReadRecord(xlogreader_state, &errormsg);
1214  if (!record)
1215  {
1216  if (!config.follow || private.endptr_reached)
1217  break;
1218  else
1219  {
1220  pg_usleep(1000000L); /* 1 second */
1221  continue;
1222  }
1223  }
1224 
1225  /* apply all specified filters */
1226  if (config.filter_by_rmgr_enabled &&
1227  !config.filter_by_rmgr[record->xl_rmid])
1228  continue;
1229 
1230  if (config.filter_by_xid_enabled &&
1231  config.filter_by_xid != record->xl_xid)
1232  continue;
1233 
1234  /* check for extended filtering */
1235  if (config.filter_by_extended &&
1236  !XLogRecordMatchesRelationBlock(xlogreader_state,
1238  config.filter_by_relation :
1241  config.filter_by_relation_block :
1244  continue;
1245 
1246  if (config.filter_by_fpw && !XLogRecordHasFPW(xlogreader_state))
1247  continue;
1248 
1249  /* perform any per-record work */
1250  if (!config.quiet)
1251  {
1252  if (config.stats == true)
1253  {
1254  XLogRecStoreStats(&stats, xlogreader_state);
1255  stats.endptr = xlogreader_state->EndRecPtr;
1256  }
1257  else
1258  XLogDumpDisplayRecord(&config, xlogreader_state);
1259  }
1260 
1261  /* save full pages if requested */
1262  if (config.save_fullpage_path != NULL)
1263  XLogRecordSaveFPWs(xlogreader_state, config.save_fullpage_path);
1264 
1265  /* check whether we printed enough */
1266  config.already_displayed_records++;
1267  if (config.stop_after_records > 0 &&
1269  break;
1270  }
1271 
1272  if (config.stats == true && !config.quiet)
1273  XLogDumpDisplayStats(&config, &stats);
1274 
1275  if (time_to_stop)
1276  exit(0);
1277 
1278  if (errormsg)
1279  pg_fatal("error in WAL record at %X/%X: %s",
1280  LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),
1281  errormsg);
1282 
1283  XLogReaderFree(xlogreader_state);
1284 
1285  return EXIT_SUCCESS;
1286 
1287 bad_argument:
1288  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
1289  return EXIT_FAILURE;
1290 }
#define InvalidBlockNumber
Definition: block.h:33
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition: block.h:71
unsigned int uint32
Definition: c.h:490
#define ngettext(s, p, n)
Definition: c.h:1171
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1204
#define OidIsValid(objectId)
Definition: c.h:759
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:460
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
#define no_argument
Definition: getopt_long.h:24
#define required_argument
Definition: getopt_long.h:25
#define optional_argument
Definition: getopt_long.h:26
#define close(a)
Definition: win32.h:12
exit(1)
void pg_logging_init(const char *argv0)
Definition: logging.c:83
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_error_hint(...)
Definition: logging.h:112
#define pg_log_error_detail(...)
Definition: logging.h:109
PGDLLIMPORT int optind
Definition: getopt.c:50
PGDLLIMPORT char * optarg
Definition: getopt.c:52
static void XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
Definition: pg_waldump.c:620
static int WalSegSz
Definition: pg_waldump.c:41
static void WALDumpCloseSegment(XLogReaderState *state)
Definition: pg_waldump.c:375
static volatile sig_atomic_t time_to_stop
Definition: pg_waldump.c:42
static void split_path(const char *path, char **dir, char **fname)
Definition: pg_waldump.c:160
static int open_file_in_directory(const char *directory, const char *fname)
Definition: pg_waldump.c:187
static void XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record)
Definition: pg_waldump.c:540
static void create_fullpage_directory(char *path)
Definition: pg_waldump.c:127
static bool verify_directory(const char *directory)
Definition: pg_waldump.c:112
static const RelFileLocator emptyRelFileLocator
Definition: pg_waldump.c:44
static void print_rmgr_list(void)
Definition: pg_waldump.c:97
static void WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
Definition: pg_waldump.c:333
static const char * progname
Definition: pg_waldump.c:39
static void usage(void)
Definition: pg_waldump.c:750
static int WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff)
Definition: pg_waldump.c:384
static void XLogRecordSaveFPWs(XLogReaderState *record, const char *savepath)
Definition: pg_waldump.c:485
static char * identify_target_directory(char *directory, char *fname)
Definition: pg_waldump.c:287
static bool XLogRecordHasFPW(XLogReaderState *record)
Definition: pg_waldump.c:464
static void sigint_handler(SIGNAL_ARGS)
Definition: pg_waldump.c:90
static bool XLogRecordMatchesRelationBlock(XLogReaderState *record, RelFileLocator matchRlocator, BlockNumber matchBlock, ForkNumber matchFork)
Definition: pg_waldump.c:433
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
const char * get_progname(const char *argv0)
Definition: path.c:574
pqsigfunc pqsignal(int signo, pqsigfunc func)
#define printf(...)
Definition: port.h:244
static int fd(const char *x, int i)
Definition: preproc-init.c:105
ForkNumber forkname_to_number(const char *forkName)
Definition: relpath.c:50
@ InvalidForkNumber
Definition: relpath.h:49
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
#define RM_MAX_BUILTIN_ID
Definition: rmgr.h:34
static bool RmgrIdIsCustom(int rmid)
Definition: rmgr.h:48
const RmgrDescData * GetRmgrDesc(RmgrId rmid)
Definition: rmgrdesc.c:87
#define EXIT_SUCCESS
Definition: settings.h:162
#define EXIT_FAILURE
Definition: settings.h:166
void pg_usleep(long microsec)
Definition: signal.c:53
RelFileNumber relNumber
bool filter_by_xid_enabled
Definition: pg_waldump.c:69
RelFileLocator filter_by_relation
Definition: pg_waldump.c:70
char * save_fullpage_path
Definition: pg_waldump.c:79
bool bkp_details
Definition: pg_waldump.c:58
bool filter_by_rmgr[RM_MAX_ID+1]
Definition: pg_waldump.c:66
bool filter_by_extended
Definition: pg_waldump.c:71
bool stats_per_record
Definition: pg_waldump.c:63
int already_displayed_records
Definition: pg_waldump.c:60
int stop_after_records
Definition: pg_waldump.c:59
bool filter_by_fpw
Definition: pg_waldump.c:76
bool filter_by_relation_enabled
Definition: pg_waldump.c:72
BlockNumber filter_by_relation_block
Definition: pg_waldump.c:73
bool filter_by_rmgr_enabled
Definition: pg_waldump.c:67
TransactionId filter_by_xid
Definition: pg_waldump.c:68
ForkNumber filter_by_relation_forknum
Definition: pg_waldump.c:75
bool filter_by_relation_block_enabled
Definition: pg_waldump.c:74
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
XLogRecPtr ReadRecPtr
Definition: xlogreader.h:206
TransactionId xl_xid
Definition: xlogrecord.h:44
RmgrId xl_rmid
Definition: xlogrecord.h:47
#define InvalidTransactionId
Definition: transam.h:31
#define XLogSegmentOffset(xlogptr, wal_segsz_bytes)
static void XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes)
#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest)
#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes)
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:43
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
uint64 XLogSegNo
Definition: xlogdefs.h:48
XLogRecord * XLogReadRecord(XLogReaderState *state, char **errormsg)
Definition: xlogreader.c:422
void XLogReaderFree(XLogReaderState *state)
Definition: xlogreader.c:170
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition: xlogreader.c:108
XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
Definition: xlogreader.c:1369
#define XL_ROUTINE(...)
Definition: xlogreader.h:117
void XLogRecStoreStats(XLogStats *stats, XLogReaderState *record)
Definition: xlogstats.c:54

References XLogDumpConfig::already_displayed_records, XLogDumpConfig::bkp_details, BlockNumberIsValid(), close, create_fullpage_directory(), RelFileLocator::dbOid, directory, emptyRelFileLocator, XLogReaderState::EndRecPtr, exit(), EXIT_FAILURE, EXIT_SUCCESS, fd(), XLogDumpConfig::filter_by_extended, XLogDumpConfig::filter_by_fpw, XLogDumpConfig::filter_by_relation, XLogDumpConfig::filter_by_relation_block, XLogDumpConfig::filter_by_relation_block_enabled, XLogDumpConfig::filter_by_relation_enabled, XLogDumpConfig::filter_by_relation_forknum, XLogDumpConfig::filter_by_rmgr, XLogDumpConfig::filter_by_rmgr_enabled, XLogDumpConfig::filter_by_xid, XLogDumpConfig::filter_by_xid_enabled, XLogDumpConfig::follow, forkname_to_number(), get_progname(), getopt_long(), GetRmgrDesc(), identify_target_directory(), InvalidBlockNumber, InvalidForkNumber, InvalidTransactionId, InvalidXLogRecPtr, LSN_FORMAT_ARGS, ngettext, no_argument, OidIsValid, open_file_in_directory(), optarg, optind, optional_argument, pg_fatal, pg_log_error, pg_log_error_detail, pg_log_error_hint, pg_logging_init(), pg_strcasecmp(), pg_strdup(), PG_TEXTDOMAIN, pg_usleep(), pqsignal(), print_rmgr_list(), printf, progname, XLogDumpConfig::quiet, XLogReaderState::ReadRecPtr, RelFileNumberIsValid, RelFileLocator::relNumber, required_argument, RM_MAX_BUILTIN_ID, RmgrIdIsCustom(), XLogDumpConfig::save_fullpage_path, set_pglocale_pgservice(), sigint_handler(), RelFileLocator::spcOid, split_path(), XLogDumpConfig::stats, XLogDumpConfig::stats_per_record, XLogDumpConfig::stop_after_records, time_to_stop, usage(), verify_directory(), WALDumpCloseSegment(), WALDumpOpenSegment(), WALDumpReadPage(), WalSegSz, XLogRecord::xl_rmid, XL_ROUTINE, XLogRecord::xl_xid, XLByteInSeg, XLogDumpDisplayRecord(), XLogDumpDisplayStats(), XLogFindNextRecord(), XLogFromFileName(), XLogReaderAllocate(), XLogReaderFree(), XLogReadRecord(), XLogRecordHasFPW(), XLogRecordMatchesRelationBlock(), XLogRecordSaveFPWs(), XLogRecPtrIsInvalid, XLogRecStoreStats(), XLogSegmentOffset, and XLogSegNoOffsetToRecPtr.

◆ open_file_in_directory()

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

Definition at line 187 of file pg_waldump.c.

188 {
189  int fd = -1;
190  char fpath[MAXPGPATH];
191 
192  Assert(directory != NULL);
193 
194  snprintf(fpath, MAXPGPATH, "%s/%s", directory, fname);
195  fd = open(fpath, O_RDONLY | PG_BINARY, 0);
196 
197  if (fd < 0 && errno != ENOENT)
198  pg_fatal("could not open file \"%s\": %m", fname);
199  return fd;
200 }
#define PG_BINARY
Definition: c.h:1260
Assert(fmt[strlen(fmt) - 1] !='\n')

References Assert(), directory, fd(), MAXPGPATH, PG_BINARY, pg_fatal, and snprintf.

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

◆ print_rmgr_list()

static void print_rmgr_list ( void  )
static

Definition at line 97 of file pg_waldump.c.

98 {
99  int i;
100 
101  for (i = 0; i <= RM_MAX_BUILTIN_ID; i++)
102  {
103  printf("%s\n", GetRmgrDesc(i)->rm_name);
104  }
105 }
int i
Definition: isn.c:73

References GetRmgrDesc(), i, printf, and RM_MAX_BUILTIN_ID.

Referenced by main().

◆ search_directory()

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

Definition at line 209 of file pg_waldump.c.

210 {
211  int fd = -1;
212  DIR *xldir;
213 
214  /* open file if valid filename is provided */
215  if (fname != NULL)
217 
218  /*
219  * A valid file name is not passed, so search the complete directory. If
220  * we find any file whose name is a valid WAL file name then try to open
221  * it. If we cannot open it, bail out.
222  */
223  else if ((xldir = opendir(directory)) != NULL)
224  {
225  struct dirent *xlde;
226 
227  while ((xlde = readdir(xldir)) != NULL)
228  {
229  if (IsXLogFileName(xlde->d_name))
230  {
232  fname = pg_strdup(xlde->d_name);
233  break;
234  }
235  }
236 
237  closedir(xldir);
238  }
239 
240  /* set WalSegSz if file is successfully opened */
241  if (fd >= 0)
242  {
244  int r;
245 
246  r = read(fd, buf.data, XLOG_BLCKSZ);
247  if (r == XLOG_BLCKSZ)
248  {
249  XLogLongPageHeader longhdr = (XLogLongPageHeader) buf.data;
250 
251  WalSegSz = longhdr->xlp_seg_size;
252 
254  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",
255  "WAL segment size must be a power of two between 1 MB and 1 GB, but the WAL file \"%s\" header specifies %d bytes",
256  WalSegSz),
257  fname, WalSegSz);
258  }
259  else if (r < 0)
260  pg_fatal("could not read file \"%s\": %m",
261  fname);
262  else
263  pg_fatal("could not read file \"%s\": read %d of %d",
264  fname, r, XLOG_BLCKSZ);
265  close(fd);
266  return true;
267  }
268 
269  return false;
270 }
int closedir(DIR *)
Definition: dirent.c:127
struct dirent * readdir(DIR *)
Definition: dirent.c:78
DIR * opendir(const char *)
Definition: dirent.c:33
#define read(a, b, c)
Definition: win32.h:13
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static char * buf
Definition: pg_test_fsync.c:67
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
#define IsValidWalSegSize(size)
Definition: xlog_internal.h:96
XLogLongPageHeaderData * XLogLongPageHeader
Definition: xlog_internal.h:71
static bool IsXLogFileName(const char *fname)

References buf, close, closedir(), dirent::d_name, directory, fd(), if(), IsValidWalSegSize, IsXLogFileName(), ngettext, open_file_in_directory(), opendir(), pg_fatal, pg_strdup(), read, readdir(), WalSegSz, and XLogLongPageHeaderData::xlp_seg_size.

Referenced by identify_target_directory().

◆ sigint_handler()

static void sigint_handler ( SIGNAL_ARGS  )
static

Definition at line 90 of file pg_waldump.c.

91 {
92  time_to_stop = true;
93 }

References time_to_stop.

Referenced by main().

◆ split_path()

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

Definition at line 160 of file pg_waldump.c.

161 {
162  char *sep;
163 
164  /* split filepath into directory & filename */
165  sep = strrchr(path, '/');
166 
167  /* directory path */
168  if (sep != NULL)
169  {
170  *dir = pnstrdup(path, sep - path);
171  *fname = pg_strdup(sep + 1);
172  }
173  /* local directory */
174  else
175  {
176  *dir = NULL;
177  *fname = pg_strdup(path);
178  }
179 }
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1635

References pg_strdup(), and pnstrdup().

Referenced by main().

◆ usage()

static void usage ( void  )
static

Definition at line 750 of file pg_waldump.c.

751 {
752  printf(_("%s decodes and displays PostgreSQL write-ahead logs for debugging.\n\n"),
753  progname);
754  printf(_("Usage:\n"));
755  printf(_(" %s [OPTION]... [STARTSEG [ENDSEG]]\n"), progname);
756  printf(_("\nOptions:\n"));
757  printf(_(" -b, --bkp-details output detailed information about backup blocks\n"));
758  printf(_(" -B, --block=N with --relation, only show records that modify block N\n"));
759  printf(_(" -e, --end=RECPTR stop reading at WAL location RECPTR\n"));
760  printf(_(" -f, --follow keep retrying after reaching end of WAL\n"));
761  printf(_(" -F, --fork=FORK only show records that modify blocks in fork FORK;\n"
762  " valid names are main, fsm, vm, init\n"));
763  printf(_(" -n, --limit=N number of records to display\n"));
764  printf(_(" -p, --path=PATH directory in which to find WAL segment files or a\n"
765  " directory with a ./pg_wal that contains such files\n"
766  " (default: current directory, ./pg_wal, $PGDATA/pg_wal)\n"));
767  printf(_(" -q, --quiet do not print any output, except for errors\n"));
768  printf(_(" -r, --rmgr=RMGR only show records generated by resource manager RMGR;\n"
769  " use --rmgr=list to list valid resource manager names\n"));
770  printf(_(" -R, --relation=T/D/R only show records that modify blocks in relation T/D/R\n"));
771  printf(_(" -s, --start=RECPTR start reading at WAL location RECPTR\n"));
772  printf(_(" -t, --timeline=TLI timeline from which to read WAL records\n"
773  " (default: 1 or the value used in STARTSEG)\n"));
774  printf(_(" -V, --version output version information, then exit\n"));
775  printf(_(" -w, --fullpage only show records with a full page write\n"));
776  printf(_(" --save-fullpage=PATH\n"
777  " save full page images\n"));
778  printf(_(" -x, --xid=XID only show records with transaction ID XID\n"));
779  printf(_(" -z, --stats[=record] show statistics instead of records\n"
780  " (optionally, show per-record statistics)\n"));
781  printf(_(" -?, --help show this help, then exit\n"));
782  printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
783  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
784 }
#define _(x)
Definition: elog.c:91

References _, printf, and progname.

Referenced by main().

◆ verify_directory()

static bool verify_directory ( const char *  directory)
static

Definition at line 112 of file pg_waldump.c.

113 {
114  DIR *dir = opendir(directory);
115 
116  if (dir == NULL)
117  return false;
118  closedir(dir);
119  return true;
120 }

References closedir(), directory, and opendir().

Referenced by main().

◆ WALDumpCloseSegment()

static void WALDumpCloseSegment ( XLogReaderState state)
static

Definition at line 375 of file pg_waldump.c.

376 {
377  close(state->seg.ws_file);
378  /* need to check errno? */
379  state->seg.ws_file = -1;
380 }
Definition: regguts.h:318

References close.

Referenced by main().

◆ WALDumpOpenSegment()

static void WALDumpOpenSegment ( XLogReaderState state,
XLogSegNo  nextSegNo,
TimeLineID tli_p 
)
static

Definition at line 333 of file pg_waldump.c.

335 {
336  TimeLineID tli = *tli_p;
337  char fname[MAXPGPATH];
338  int tries;
339 
340  XLogFileName(fname, tli, nextSegNo, state->segcxt.ws_segsize);
341 
342  /*
343  * In follow mode there is a short period of time after the server has
344  * written the end of the previous file before the new file is available.
345  * So we loop for 5 seconds looking for the file to appear before giving
346  * up.
347  */
348  for (tries = 0; tries < 10; tries++)
349  {
350  state->seg.ws_file = open_file_in_directory(state->segcxt.ws_dir, fname);
351  if (state->seg.ws_file >= 0)
352  return;
353  if (errno == ENOENT)
354  {
355  int save_errno = errno;
356 
357  /* File not there yet, try again */
358  pg_usleep(500 * 1000);
359 
360  errno = save_errno;
361  continue;
362  }
363  /* Any other error, fall through and fail */
364  break;
365  }
366 
367  pg_fatal("could not find file \"%s\": %m", fname);
368 }
static void XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
uint32 TimeLineID
Definition: xlogdefs.h:59

References MAXPGPATH, open_file_in_directory(), pg_fatal, pg_usleep(), and XLogFileName().

Referenced by main().

◆ WALDumpReadPage()

static int WALDumpReadPage ( XLogReaderState state,
XLogRecPtr  targetPagePtr,
int  reqLen,
XLogRecPtr  targetPtr,
char *  readBuff 
)
static

Definition at line 384 of file pg_waldump.c.

386 {
387  XLogDumpPrivate *private = state->private_data;
388  int count = XLOG_BLCKSZ;
389  WALReadError errinfo;
390 
391  if (private->endptr != InvalidXLogRecPtr)
392  {
393  if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
394  count = XLOG_BLCKSZ;
395  else if (targetPagePtr + reqLen <= private->endptr)
396  count = private->endptr - targetPagePtr;
397  else
398  {
399  private->endptr_reached = true;
400  return -1;
401  }
402  }
403 
404  if (!WALRead(state, readBuff, targetPagePtr, count, private->timeline,
405  &errinfo))
406  {
407  WALOpenSegment *seg = &errinfo.wre_seg;
408  char fname[MAXPGPATH];
409 
410  XLogFileName(fname, seg->ws_tli, seg->ws_segno,
411  state->segcxt.ws_segsize);
412 
413  if (errinfo.wre_errno != 0)
414  {
415  errno = errinfo.wre_errno;
416  pg_fatal("could not read from file %s, offset %d: %m",
417  fname, errinfo.wre_off);
418  }
419  else
420  pg_fatal("could not read from file %s, offset %d: read %d of %d",
421  fname, errinfo.wre_off, errinfo.wre_read,
422  errinfo.wre_req);
423  }
424 
425  return count;
426 }
XLogSegNo ws_segno
Definition: xlogreader.h:48
TimeLineID ws_tli
Definition: xlogreader.h:49
WALOpenSegment wre_seg
Definition: xlogreader.h:387
bool WALRead(XLogReaderState *state, char *buf, XLogRecPtr startptr, Size count, TimeLineID tli, WALReadError *errinfo)
Definition: xlogreader.c:1492

References InvalidXLogRecPtr, MAXPGPATH, pg_fatal, WALRead(), WALReadError::wre_errno, WALReadError::wre_off, WALReadError::wre_read, WALReadError::wre_req, WALReadError::wre_seg, WALOpenSegment::ws_segno, WALOpenSegment::ws_tli, and XLogFileName().

Referenced by main().

◆ XLogDumpDisplayRecord()

static void XLogDumpDisplayRecord ( XLogDumpConfig config,
XLogReaderState record 
)
static

Definition at line 540 of file pg_waldump.c.

541 {
542  const char *id;
543  const RmgrDescData *desc = GetRmgrDesc(XLogRecGetRmid(record));
544  uint32 rec_len;
545  uint32 fpi_len;
546  uint8 info = XLogRecGetInfo(record);
547  XLogRecPtr xl_prev = XLogRecGetPrev(record);
548  StringInfoData s;
549 
550  XLogRecGetLen(record, &rec_len, &fpi_len);
551 
552  printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
553  desc->rm_name,
554  rec_len, XLogRecGetTotalLen(record),
555  XLogRecGetXid(record),
556  LSN_FORMAT_ARGS(record->ReadRecPtr),
557  LSN_FORMAT_ARGS(xl_prev));
558 
559  id = desc->rm_identify(info);
560  if (id == NULL)
561  printf("desc: UNKNOWN (%x) ", info & ~XLR_INFO_MASK);
562  else
563  printf("desc: %s ", id);
564 
565  initStringInfo(&s);
566  desc->rm_desc(&s, record);
567  printf("%s", s.data);
568 
569  resetStringInfo(&s);
570  XLogRecGetBlockRefInfo(record, true, config->bkp_details, &s, NULL);
571  printf("%s", s.data);
572  pfree(s.data);
573 }
unsigned char uint8
Definition: c.h:488
void pfree(void *pointer)
Definition: mcxt.c:1436
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:75
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
const char *(* rm_identify)(uint8 info)
Definition: rmgrdesc.h:18
const char * rm_name
Definition: rmgrdesc.h:16
void(* rm_desc)(StringInfo buf, XLogReaderState *record)
Definition: rmgrdesc.h:17
void XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty, bool detailed_format, StringInfo buf, uint32 *fpi_len)
Definition: xlogdesc.c:209
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:409
#define XLogRecGetRmid(decoder)
Definition: xlogreader.h:410
#define XLogRecGetTotalLen(decoder)
Definition: xlogreader.h:407
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:411
#define XLogRecGetPrev(decoder)
Definition: xlogreader.h:408
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
void XLogRecGetLen(XLogReaderState *record, uint32 *rec_len, uint32 *fpi_len)
Definition: xlogstats.c:22

References XLogDumpConfig::bkp_details, StringInfoData::data, GetRmgrDesc(), initStringInfo(), LSN_FORMAT_ARGS, pfree(), printf, XLogReaderState::ReadRecPtr, resetStringInfo(), RmgrDescData::rm_desc, RmgrDescData::rm_identify, RmgrDescData::rm_name, XLogRecGetBlockRefInfo(), XLogRecGetInfo, XLogRecGetLen(), XLogRecGetPrev, XLogRecGetRmid, XLogRecGetTotalLen, XLogRecGetXid, and XLR_INFO_MASK.

Referenced by main().

◆ XLogDumpDisplayStats()

static void XLogDumpDisplayStats ( XLogDumpConfig config,
XLogStats stats 
)
static

Definition at line 620 of file pg_waldump.c.

621 {
622  int ri,
623  rj;
624  uint64 total_count = 0;
625  uint64 total_rec_len = 0;
626  uint64 total_fpi_len = 0;
627  uint64 total_len = 0;
628  double rec_len_pct,
629  fpi_len_pct;
630 
631  /*
632  * Leave if no stats have been computed yet, as tracked by the end LSN.
633  */
634  if (XLogRecPtrIsInvalid(stats->endptr))
635  return;
636 
637  /*
638  * Each row shows its percentages of the total, so make a first pass to
639  * calculate column totals.
640  */
641 
642  for (ri = 0; ri <= RM_MAX_ID; ri++)
643  {
644  if (!RmgrIdIsValid(ri))
645  continue;
646 
647  total_count += stats->rmgr_stats[ri].count;
648  total_rec_len += stats->rmgr_stats[ri].rec_len;
649  total_fpi_len += stats->rmgr_stats[ri].fpi_len;
650  }
651  total_len = total_rec_len + total_fpi_len;
652 
653  printf("WAL statistics between %X/%X and %X/%X:\n",
654  LSN_FORMAT_ARGS(stats->startptr), LSN_FORMAT_ARGS(stats->endptr));
655 
656  /*
657  * 27 is strlen("Transaction/COMMIT_PREPARED"), 20 is strlen(2^64), 8 is
658  * strlen("(100.00%)")
659  */
660 
661  printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
662  "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
663  "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
664  "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
665 
666  for (ri = 0; ri <= RM_MAX_ID; ri++)
667  {
668  uint64 count,
669  rec_len,
670  fpi_len,
671  tot_len;
672  const RmgrDescData *desc;
673 
674  if (!RmgrIdIsValid(ri))
675  continue;
676 
677  desc = GetRmgrDesc(ri);
678 
679  if (!config->stats_per_record)
680  {
681  count = stats->rmgr_stats[ri].count;
682  rec_len = stats->rmgr_stats[ri].rec_len;
683  fpi_len = stats->rmgr_stats[ri].fpi_len;
684  tot_len = rec_len + fpi_len;
685 
686  if (RmgrIdIsCustom(ri) && count == 0)
687  continue;
688 
690  count, total_count, rec_len, total_rec_len,
691  fpi_len, total_fpi_len, tot_len, total_len);
692  }
693  else
694  {
695  for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
696  {
697  const char *id;
698 
699  count = stats->record_stats[ri][rj].count;
700  rec_len = stats->record_stats[ri][rj].rec_len;
701  fpi_len = stats->record_stats[ri][rj].fpi_len;
702  tot_len = rec_len + fpi_len;
703 
704  /* Skip undefined combinations and ones that didn't occur */
705  if (count == 0)
706  continue;
707 
708  /* the upper four bits in xl_info are the rmgr's */
709  id = desc->rm_identify(rj << 4);
710  if (id == NULL)
711  id = psprintf("UNKNOWN (%x)", rj << 4);
712 
713  XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
714  count, total_count, rec_len, total_rec_len,
715  fpi_len, total_fpi_len, tot_len, total_len);
716  }
717  }
718  }
719 
720  printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
721  "", "--------", "", "--------", "", "--------", "", "--------");
722 
723  /*
724  * The percentages in earlier rows were calculated against the column
725  * total, but the ones that follow are against the row total. Note that
726  * these are displayed with a % symbol to differentiate them from the
727  * earlier ones, and are thus up to 9 characters long.
728  */
729 
730  rec_len_pct = 0;
731  if (total_len != 0)
732  rec_len_pct = 100 * (double) total_rec_len / total_len;
733 
734  fpi_len_pct = 0;
735  if (total_len != 0)
736  fpi_len_pct = 100 * (double) total_fpi_len / total_len;
737 
738  printf("%-27s "
739  "%20" INT64_MODIFIER "u %-9s"
740  "%20" INT64_MODIFIER "u %-9s"
741  "%20" INT64_MODIFIER "u %-9s"
742  "%20" INT64_MODIFIER "u %-6s\n",
743  "Total", stats->count, "",
744  total_rec_len, psprintf("[%.02f%%]", rec_len_pct),
745  total_fpi_len, psprintf("[%.02f%%]", fpi_len_pct),
746  total_len, "[100%]");
747 }
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:579
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define RmgrIdIsValid(rmid)
Definition: rmgr.h:53
#define RM_MAX_ID
Definition: rmgr.h:33
uint64 count
Definition: xlogstats.h:23
uint64 fpi_len
Definition: xlogstats.h:25
uint64 rec_len
Definition: xlogstats.h:24
XLogRecStats record_stats[RM_MAX_ID+1][MAX_XLINFO_TYPES]
Definition: xlogstats.h:36
uint64 count
Definition: xlogstats.h:30
XLogRecStats rmgr_stats[RM_MAX_ID+1]
Definition: xlogstats.h:35
#define MAX_XLINFO_TYPES
Definition: xlogstats.h:19

References XLogRecStats::count, XLogStats::count, XLogRecStats::fpi_len, GetRmgrDesc(), LSN_FORMAT_ARGS, MAX_XLINFO_TYPES, printf, psprintf(), XLogRecStats::rec_len, XLogStats::record_stats, RmgrDescData::rm_identify, RM_MAX_ID, RmgrDescData::rm_name, XLogStats::rmgr_stats, RmgrIdIsCustom(), RmgrIdIsValid, XLogDumpConfig::stats_per_record, XLogDumpStatsRow(), and XLogRecPtrIsInvalid.

Referenced by main().

◆ 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 579 of file pg_waldump.c.

584 {
585  double n_pct,
586  rec_len_pct,
587  fpi_len_pct,
588  tot_len_pct;
589 
590  n_pct = 0;
591  if (total_count != 0)
592  n_pct = 100 * (double) n / total_count;
593 
594  rec_len_pct = 0;
595  if (total_rec_len != 0)
596  rec_len_pct = 100 * (double) rec_len / total_rec_len;
597 
598  fpi_len_pct = 0;
599  if (total_fpi_len != 0)
600  fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
601 
602  tot_len_pct = 0;
603  if (total_len != 0)
604  tot_len_pct = 100 * (double) tot_len / total_len;
605 
606  printf("%-27s "
607  "%20" INT64_MODIFIER "u (%6.02f) "
608  "%20" INT64_MODIFIER "u (%6.02f) "
609  "%20" INT64_MODIFIER "u (%6.02f) "
610  "%20" INT64_MODIFIER "u (%6.02f)\n",
611  name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
612  tot_len, tot_len_pct);
613 }
const char * name
Definition: encode.c:571

References name, and printf.

Referenced by XLogDumpDisplayStats().

◆ XLogRecordHasFPW()

static bool XLogRecordHasFPW ( XLogReaderState record)
static

Definition at line 464 of file pg_waldump.c.

465 {
466  int block_id;
467 
468  for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
469  {
470  if (!XLogRecHasBlockRef(record, block_id))
471  continue;
472 
473  if (XLogRecHasBlockImage(record, block_id))
474  return true;
475  }
476 
477  return false;
478 }
#define XLogRecMaxBlockId(decoder)
Definition: xlogreader.h:417
#define XLogRecHasBlockImage(decoder, block_id)
Definition: xlogreader.h:422
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:419

References XLogRecHasBlockImage, XLogRecHasBlockRef, and XLogRecMaxBlockId.

Referenced by main().

◆ XLogRecordMatchesRelationBlock()

static bool XLogRecordMatchesRelationBlock ( XLogReaderState record,
RelFileLocator  matchRlocator,
BlockNumber  matchBlock,
ForkNumber  matchFork 
)
static

Definition at line 433 of file pg_waldump.c.

437 {
438  int block_id;
439 
440  for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
441  {
442  RelFileLocator rlocator;
443  ForkNumber forknum;
444  BlockNumber blk;
445 
446  if (!XLogRecGetBlockTagExtended(record, block_id,
447  &rlocator, &forknum, &blk, NULL))
448  continue;
449 
450  if ((matchFork == InvalidForkNumber || matchFork == forknum) &&
451  (RelFileLocatorEquals(matchRlocator, emptyRelFileLocator) ||
452  RelFileLocatorEquals(matchRlocator, rlocator)) &&
453  (matchBlock == InvalidBlockNumber || matchBlock == blk))
454  return true;
455  }
456 
457  return false;
458 }
uint32 BlockNumber
Definition: block.h:31
#define RelFileLocatorEquals(locator1, locator2)
ForkNumber
Definition: relpath.h:48
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)
Definition: xlogreader.c:1986

References emptyRelFileLocator, InvalidBlockNumber, InvalidForkNumber, RelFileLocatorEquals, XLogRecGetBlockTagExtended(), and XLogRecMaxBlockId.

Referenced by main().

◆ XLogRecordSaveFPWs()

static void XLogRecordSaveFPWs ( XLogReaderState record,
const char *  savepath 
)
static

Definition at line 485 of file pg_waldump.c.

486 {
487  int block_id;
488 
489  for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
490  {
492  Page page;
493  char filename[MAXPGPATH];
494  char forkname[FORKNAMECHARS + 2]; /* _ + terminating zero */
495  FILE *file;
496  BlockNumber blk;
497  RelFileLocator rnode;
498  ForkNumber fork;
499 
500  if (!XLogRecHasBlockRef(record, block_id))
501  continue;
502 
503  if (!XLogRecHasBlockImage(record, block_id))
504  continue;
505 
506  page = (Page) buf.data;
507 
508  /* Full page exists, so let's save it */
509  if (!RestoreBlockImage(record, block_id, page))
510  pg_fatal("%s", record->errormsg_buf);
511 
512  (void) XLogRecGetBlockTagExtended(record, block_id,
513  &rnode, &fork, &blk, NULL);
514 
515  if (fork >= 0 && fork <= MAX_FORKNUM)
516  sprintf(forkname, "_%s", forkNames[fork]);
517  else
518  pg_fatal("invalid fork number: %u", fork);
519 
520  snprintf(filename, MAXPGPATH, "%s/%08X-%08X.%u.%u.%u.%u%s", savepath,
521  LSN_FORMAT_ARGS(record->ReadRecPtr),
522  rnode.spcOid, rnode.dbOid, rnode.relNumber, blk, forkname);
523 
524  file = fopen(filename, PG_BINARY_W);
525  if (!file)
526  pg_fatal("could not open file \"%s\": %m", filename);
527 
528  if (fwrite(page, BLCKSZ, 1, file) != 1)
529  pg_fatal("could not write file \"%s\": %m", filename);
530 
531  if (fclose(file) != 0)
532  pg_fatal("could not close file \"%s\": %m", filename);
533  }
534 }
Pointer Page
Definition: bufpage.h:78
#define PG_BINARY_W
Definition: c.h:1263
static char * filename
Definition: pg_dumpall.c:119
#define sprintf
Definition: port.h:240
const char *const forkNames[]
Definition: relpath.c:33
#define MAX_FORKNUM
Definition: relpath.h:62
#define FORKNAMECHARS
Definition: relpath.h:64
char * errormsg_buf
Definition: xlogreader.h:311
bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
Definition: xlogreader.c:2045

References buf, RelFileLocator::dbOid, XLogReaderState::errormsg_buf, filename, FORKNAMECHARS, forkNames, if(), LSN_FORMAT_ARGS, MAX_FORKNUM, MAXPGPATH, PG_BINARY_W, pg_fatal, XLogReaderState::ReadRecPtr, RelFileLocator::relNumber, RestoreBlockImage(), snprintf, RelFileLocator::spcOid, sprintf, XLogRecGetBlockTagExtended(), XLogRecHasBlockImage, XLogRecHasBlockRef, and XLogRecMaxBlockId.

Referenced by main().

Variable Documentation

◆ emptyRelFileLocator

const RelFileLocator emptyRelFileLocator = {0, 0, 0}
static

Definition at line 44 of file pg_waldump.c.

Referenced by main(), and XLogRecordMatchesRelationBlock().

◆ progname

const char* progname
static

Definition at line 39 of file pg_waldump.c.

Referenced by main(), and usage().

◆ time_to_stop

volatile sig_atomic_t time_to_stop = false
static

Definition at line 42 of file pg_waldump.c.

Referenced by main(), and sigint_handler().

◆ WalSegSz

int WalSegSz
static

Definition at line 41 of file pg_waldump.c.

Referenced by main(), and search_directory().