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/logging.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
 

Macros

#define FRONTEND   1
 

Typedefs

typedef struct XLogDumpPrivate XLogDumpPrivate
 
typedef struct XLogDumpConfig XLogDumpConfig
 

Functions

static void sigint_handler (int signum)
 
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 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, RelFileNode matchRnode, BlockNumber matchBlock, ForkNumber matchFork)
 
static bool XLogRecordHasFPW (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, 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 RelFileNode emptyRelFileNode = {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

◆ identify_target_directory()

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

Definition at line 249 of file pg_waldump.c.

250 {
251  char fpath[MAXPGPATH];
252 
253  if (directory != NULL)
254  {
255  if (search_directory(directory, fname))
256  return pg_strdup(directory);
257 
258  /* directory / XLOGDIR */
259  snprintf(fpath, MAXPGPATH, "%s/%s", directory, XLOGDIR);
260  if (search_directory(fpath, fname))
261  return pg_strdup(fpath);
262  }
263  else
264  {
265  const char *datadir;
266 
267  /* current directory */
268  if (search_directory(".", fname))
269  return pg_strdup(".");
270  /* XLOGDIR */
271  if (search_directory(XLOGDIR, fname))
272  return pg_strdup(XLOGDIR);
273 
274  datadir = getenv("PGDATA");
275  /* $PGDATA / XLOGDIR */
276  if (datadir != NULL)
277  {
278  snprintf(fpath, MAXPGPATH, "%s/%s", datadir, XLOGDIR);
279  if (search_directory(fpath, fname))
280  return pg_strdup(fpath);
281  }
282  }
283 
284  /* could not locate WAL file */
285  if (fname)
286  pg_fatal("could not locate WAL file \"%s\"", fname);
287  else
288  pg_fatal("could not find any WAL file");
289 
290  return NULL; /* not reached */
291 }
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define pg_fatal(...)
#define MAXPGPATH
char * datadir
static bool search_directory(const char *directory, const char *fname)
Definition: pg_waldump.c:171
#define snprintf
Definition: port.h:225
#define XLOGDIR
static const char * directory
Definition: zic.c:632

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

692 {
693  uint32 xlogid;
694  uint32 xrecoff;
695  XLogReaderState *xlogreader_state;
696  XLogDumpPrivate private;
697  XLogDumpConfig config;
698  XLogStats stats;
699  XLogRecord *record;
700  XLogRecPtr first_record;
701  char *waldir = NULL;
702  char *errormsg;
703 
704  static struct option long_options[] = {
705  {"bkp-details", no_argument, NULL, 'b'},
706  {"block", required_argument, NULL, 'B'},
707  {"end", required_argument, NULL, 'e'},
708  {"follow", no_argument, NULL, 'f'},
709  {"fork", required_argument, NULL, 'F'},
710  {"fullpage", no_argument, NULL, 'w'},
711  {"help", no_argument, NULL, '?'},
712  {"limit", required_argument, NULL, 'n'},
713  {"path", required_argument, NULL, 'p'},
714  {"quiet", no_argument, NULL, 'q'},
715  {"relation", required_argument, NULL, 'R'},
716  {"rmgr", required_argument, NULL, 'r'},
717  {"start", required_argument, NULL, 's'},
718  {"timeline", required_argument, NULL, 't'},
719  {"xid", required_argument, NULL, 'x'},
720  {"version", no_argument, NULL, 'V'},
721  {"stats", optional_argument, NULL, 'z'},
722  {NULL, 0, NULL, 0}
723  };
724 
725  int option;
726  int optindex = 0;
727 
728 #ifndef WIN32
729  pqsignal(SIGINT, sigint_handler);
730 #endif
731 
732  pg_logging_init(argv[0]);
733  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump"));
734  progname = get_progname(argv[0]);
735 
736  if (argc > 1)
737  {
738  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
739  {
740  usage();
741  exit(0);
742  }
743  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
744  {
745  puts("pg_waldump (PostgreSQL) " PG_VERSION);
746  exit(0);
747  }
748  }
749 
750  memset(&private, 0, sizeof(XLogDumpPrivate));
751  memset(&config, 0, sizeof(XLogDumpConfig));
752  memset(&stats, 0, sizeof(XLogStats));
753 
754  private.timeline = 1;
755  private.startptr = InvalidXLogRecPtr;
756  private.endptr = InvalidXLogRecPtr;
757  private.endptr_reached = false;
758 
759  config.quiet = false;
760  config.bkp_details = false;
761  config.stop_after_records = -1;
762  config.already_displayed_records = 0;
763  config.follow = false;
764  /* filter_by_rmgr array was zeroed by memset above */
765  config.filter_by_rmgr_enabled = false;
767  config.filter_by_xid_enabled = false;
768  config.filter_by_extended = false;
769  config.filter_by_relation_enabled = false;
770  config.filter_by_relation_block_enabled = false;
772  config.filter_by_fpw = false;
773  config.stats = false;
774  config.stats_per_record = false;
775 
776  stats.startptr = InvalidXLogRecPtr;
777  stats.endptr = InvalidXLogRecPtr;
778 
779  if (argc <= 1)
780  {
781  pg_log_error("no arguments specified");
782  goto bad_argument;
783  }
784 
785  while ((option = getopt_long(argc, argv, "bB:e:fF:n:p:qr:R:s:t:wx:z",
786  long_options, &optindex)) != -1)
787  {
788  switch (option)
789  {
790  case 'b':
791  config.bkp_details = true;
792  break;
793  case 'B':
794  if (sscanf(optarg, "%u", &config.filter_by_relation_block) != 1 ||
796  {
797  pg_log_error("invalid block number: \"%s\"", optarg);
798  goto bad_argument;
799  }
800  config.filter_by_relation_block_enabled = true;
801  config.filter_by_extended = true;
802  break;
803  case 'e':
804  if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2)
805  {
806  pg_log_error("invalid WAL location: \"%s\"",
807  optarg);
808  goto bad_argument;
809  }
810  private.endptr = (uint64) xlogid << 32 | xrecoff;
811  break;
812  case 'f':
813  config.follow = true;
814  break;
815  case 'F':
818  {
819  pg_log_error("invalid fork name: \"%s\"", optarg);
820  goto bad_argument;
821  }
822  config.filter_by_extended = true;
823  break;
824  case 'n':
825  if (sscanf(optarg, "%d", &config.stop_after_records) != 1)
826  {
827  pg_log_error("invalid value \"%s\" for option %s", optarg, "-n/--limit");
828  goto bad_argument;
829  }
830  break;
831  case 'p':
832  waldir = pg_strdup(optarg);
833  break;
834  case 'q':
835  config.quiet = true;
836  break;
837  case 'r':
838  {
839  int rmid;
840 
841  if (pg_strcasecmp(optarg, "list") == 0)
842  {
843  print_rmgr_list();
845  }
846 
847  /*
848  * First look for the generated name of a custom rmgr, of
849  * the form "custom###". We accept this form, because the
850  * custom rmgr module is not loaded, so there's no way to
851  * know the real name. This convention should be
852  * consistent with that in rmgrdesc.c.
853  */
854  if (sscanf(optarg, "custom%03d", &rmid) == 1)
855  {
856  if (!RmgrIdIsCustom(rmid))
857  {
858  pg_log_error("custom resource manager \"%s\" does not exist",
859  optarg);
860  goto bad_argument;
861  }
862  config.filter_by_rmgr[rmid] = true;
863  config.filter_by_rmgr_enabled = true;
864  }
865  else
866  {
867  /* then look for builtin rmgrs */
868  for (rmid = 0; rmid <= RM_MAX_BUILTIN_ID; rmid++)
869  {
870  if (pg_strcasecmp(optarg, GetRmgrDesc(rmid)->rm_name) == 0)
871  {
872  config.filter_by_rmgr[rmid] = true;
873  config.filter_by_rmgr_enabled = true;
874  break;
875  }
876  }
877  if (rmid > RM_MAX_BUILTIN_ID)
878  {
879  pg_log_error("resource manager \"%s\" does not exist",
880  optarg);
881  goto bad_argument;
882  }
883  }
884  }
885  break;
886  case 'R':
887  if (sscanf(optarg, "%u/%u/%u",
888  &config.filter_by_relation.spcNode,
889  &config.filter_by_relation.dbNode,
890  &config.filter_by_relation.relNode) != 3 ||
893  {
894  pg_log_error("invalid relation specification: \"%s\"", optarg);
895  pg_log_error_detail("Expecting \"tablespace OID/database OID/relation filenode\".");
896  goto bad_argument;
897  }
898  config.filter_by_relation_enabled = true;
899  config.filter_by_extended = true;
900  break;
901  case 's':
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  else
909  private.startptr = (uint64) xlogid << 32 | xrecoff;
910  break;
911  case 't':
912  if (sscanf(optarg, "%u", &private.timeline) != 1)
913  {
914  pg_log_error("invalid timeline specification: \"%s\"", optarg);
915  goto bad_argument;
916  }
917  break;
918  case 'w':
919  config.filter_by_fpw = true;
920  break;
921  case 'x':
922  if (sscanf(optarg, "%u", &config.filter_by_xid) != 1)
923  {
924  pg_log_error("invalid transaction ID specification: \"%s\"",
925  optarg);
926  goto bad_argument;
927  }
928  config.filter_by_xid_enabled = true;
929  break;
930  case 'z':
931  config.stats = true;
932  config.stats_per_record = false;
933  if (optarg)
934  {
935  if (strcmp(optarg, "record") == 0)
936  config.stats_per_record = true;
937  else if (strcmp(optarg, "rmgr") != 0)
938  {
939  pg_log_error("unrecognized value for option %s: %s",
940  "--stats", optarg);
941  goto bad_argument;
942  }
943  }
944  break;
945  default:
946  goto bad_argument;
947  }
948  }
949 
952  {
953  pg_log_error("option %s requires option %s to be specified",
954  "-B/--block", "-R/--relation");
955  goto bad_argument;
956  }
957 
958  if ((optind + 2) < argc)
959  {
960  pg_log_error("too many command-line arguments (first is \"%s\")",
961  argv[optind + 2]);
962  goto bad_argument;
963  }
964 
965  if (waldir != NULL)
966  {
967  /* validate path points to directory */
968  if (!verify_directory(waldir))
969  {
970  pg_log_error("could not open directory \"%s\": %m", waldir);
971  goto bad_argument;
972  }
973  }
974 
975  /* parse files as start/end boundaries, extract path if not specified */
976  if (optind < argc)
977  {
978  char *directory = NULL;
979  char *fname = NULL;
980  int fd;
981  XLogSegNo segno;
982 
983  split_path(argv[optind], &directory, &fname);
984 
985  if (waldir == NULL && directory != NULL)
986  {
987  waldir = directory;
988 
989  if (!verify_directory(waldir))
990  pg_fatal("could not open directory \"%s\": %m", waldir);
991  }
992 
993  waldir = identify_target_directory(waldir, fname);
994  fd = open_file_in_directory(waldir, fname);
995  if (fd < 0)
996  pg_fatal("could not open file \"%s\"", fname);
997  close(fd);
998 
999  /* parse position from file */
1000  XLogFromFileName(fname, &private.timeline, &segno, WalSegSz);
1001 
1002  if (XLogRecPtrIsInvalid(private.startptr))
1003  XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr);
1004  else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
1005  {
1006  pg_log_error("start WAL location %X/%X is not inside file \"%s\"",
1007  LSN_FORMAT_ARGS(private.startptr),
1008  fname);
1009  goto bad_argument;
1010  }
1011 
1012  /* no second file specified, set end position */
1013  if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr))
1014  XLogSegNoOffsetToRecPtr(segno + 1, 0, WalSegSz, private.endptr);
1015 
1016  /* parse ENDSEG if passed */
1017  if (optind + 1 < argc)
1018  {
1019  XLogSegNo endsegno;
1020 
1021  /* ignore directory, already have that */
1022  split_path(argv[optind + 1], &directory, &fname);
1023 
1024  fd = open_file_in_directory(waldir, fname);
1025  if (fd < 0)
1026  pg_fatal("could not open file \"%s\"", fname);
1027  close(fd);
1028 
1029  /* parse position from file */
1030  XLogFromFileName(fname, &private.timeline, &endsegno, WalSegSz);
1031 
1032  if (endsegno < segno)
1033  pg_fatal("ENDSEG %s is before STARTSEG %s",
1034  argv[optind + 1], argv[optind]);
1035 
1036  if (XLogRecPtrIsInvalid(private.endptr))
1037  XLogSegNoOffsetToRecPtr(endsegno + 1, 0, WalSegSz,
1038  private.endptr);
1039 
1040  /* set segno to endsegno for check of --end */
1041  segno = endsegno;
1042  }
1043 
1044 
1045  if (!XLByteInSeg(private.endptr, segno, WalSegSz) &&
1046  private.endptr != (segno + 1) * WalSegSz)
1047  {
1048  pg_log_error("end WAL location %X/%X is not inside file \"%s\"",
1049  LSN_FORMAT_ARGS(private.endptr),
1050  argv[argc - 1]);
1051  goto bad_argument;
1052  }
1053  }
1054  else
1055  waldir = identify_target_directory(waldir, NULL);
1056 
1057  /* we don't know what to print */
1058  if (XLogRecPtrIsInvalid(private.startptr))
1059  {
1060  pg_log_error("no start WAL location given");
1061  goto bad_argument;
1062  }
1063 
1064  /* done with argument parsing, do the actual work */
1065 
1066  /* we have everything we need, start reading */
1067  xlogreader_state =
1068  XLogReaderAllocate(WalSegSz, waldir,
1069  XL_ROUTINE(.page_read = WALDumpReadPage,
1070  .segment_open = WALDumpOpenSegment,
1071  .segment_close = WALDumpCloseSegment),
1072  &private);
1073  if (!xlogreader_state)
1074  pg_fatal("out of memory while allocating a WAL reading processor");
1075 
1076  /* first find a valid recptr to start from */
1077  first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
1078 
1079  if (first_record == InvalidXLogRecPtr)
1080  pg_fatal("could not find a valid record after %X/%X",
1081  LSN_FORMAT_ARGS(private.startptr));
1082 
1083  /*
1084  * Display a message that we're skipping data if `from` wasn't a pointer
1085  * to the start of a record and also wasn't a pointer to the beginning of
1086  * a segment (e.g. we were used in file mode).
1087  */
1088  if (first_record != private.startptr &&
1089  XLogSegmentOffset(private.startptr, WalSegSz) != 0)
1090  printf(ngettext("first record is after %X/%X, at %X/%X, skipping over %u byte\n",
1091  "first record is after %X/%X, at %X/%X, skipping over %u bytes\n",
1092  (first_record - private.startptr)),
1093  LSN_FORMAT_ARGS(private.startptr),
1094  LSN_FORMAT_ARGS(first_record),
1095  (uint32) (first_record - private.startptr));
1096 
1097  if (config.stats == true && !config.quiet)
1098  stats.startptr = first_record;
1099 
1100  for (;;)
1101  {
1102  if (time_to_stop)
1103  {
1104  /* We've been Ctrl-C'ed, so leave */
1105  break;
1106  }
1107 
1108  /* try to read the next record */
1109  record = XLogReadRecord(xlogreader_state, &errormsg);
1110  if (!record)
1111  {
1112  if (!config.follow || private.endptr_reached)
1113  break;
1114  else
1115  {
1116  pg_usleep(1000000L); /* 1 second */
1117  continue;
1118  }
1119  }
1120 
1121  /* apply all specified filters */
1122  if (config.filter_by_rmgr_enabled &&
1123  !config.filter_by_rmgr[record->xl_rmid])
1124  continue;
1125 
1126  if (config.filter_by_xid_enabled &&
1127  config.filter_by_xid != record->xl_xid)
1128  continue;
1129 
1130  /* check for extended filtering */
1131  if (config.filter_by_extended &&
1132  !XLogRecordMatchesRelationBlock(xlogreader_state,
1134  config.filter_by_relation :
1137  config.filter_by_relation_block :
1140  continue;
1141 
1142  if (config.filter_by_fpw && !XLogRecordHasFPW(xlogreader_state))
1143  continue;
1144 
1145  /* perform any per-record work */
1146  if (!config.quiet)
1147  {
1148  if (config.stats == true)
1149  {
1150  XLogRecStoreStats(&stats, xlogreader_state);
1151  stats.endptr = xlogreader_state->EndRecPtr;
1152  }
1153  else
1154  XLogDumpDisplayRecord(&config, xlogreader_state);
1155  }
1156 
1157  /* check whether we printed enough */
1158  config.already_displayed_records++;
1159  if (config.stop_after_records > 0 &&
1161  break;
1162  }
1163 
1164  if (config.stats == true && !config.quiet)
1165  XLogDumpDisplayStats(&config, &stats);
1166 
1167  if (time_to_stop)
1168  exit(0);
1169 
1170  if (errormsg)
1171  pg_fatal("error in WAL record at %X/%X: %s",
1172  LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),
1173  errormsg);
1174 
1175  XLogReaderFree(xlogreader_state);
1176 
1177  return EXIT_SUCCESS;
1178 
1179 bad_argument:
1180  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
1181  return EXIT_FAILURE;
1182 }
#define InvalidBlockNumber
Definition: block.h:33
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
unsigned int uint32
Definition: c.h:441
#define ngettext(s, p, n)
Definition: c.h:1179
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1212
#define OidIsValid(objectId)
Definition: c.h:710
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:446
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:526
static int WalSegSz
Definition: pg_waldump.c:37
static void WALDumpCloseSegment(XLogReaderState *state)
Definition: pg_waldump.c:337
static void sigint_handler(int signum)
Definition: pg_waldump.c:83
static volatile sig_atomic_t time_to_stop
Definition: pg_waldump.c:38
static void split_path(const char *path, char **dir, char **fname)
Definition: pg_waldump.c:122
static int open_file_in_directory(const char *directory, const char *fname)
Definition: pg_waldump.c:149
static void XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record)
Definition: pg_waldump.c:446
static bool XLogRecordMatchesRelationBlock(XLogReaderState *record, RelFileNode matchRnode, BlockNumber matchBlock, ForkNumber matchFork)
Definition: pg_waldump.c:395
static bool verify_directory(const char *directory)
Definition: pg_waldump.c:105
static void print_rmgr_list(void)
Definition: pg_waldump.c:90
static void WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
Definition: pg_waldump.c:295
static const char * progname
Definition: pg_waldump.c:35
static void usage(void)
Definition: pg_waldump.c:656
static int WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff)
Definition: pg_waldump.c:346
static const RelFileNode emptyRelFileNode
Definition: pg_waldump.c:40
static char * identify_target_directory(char *directory, char *fname)
Definition: pg_waldump.c:249
static bool XLogRecordHasFPW(XLogReaderState *record)
Definition: pg_waldump.c:426
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
const char * get_progname(const char *argv0)
Definition: path.c:574
#define printf(...)
Definition: port.h:231
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:42
#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:159
#define EXIT_FAILURE
Definition: settings.h:163
void pg_usleep(long microsec)
Definition: signal.c:53
pqsigfunc pqsignal(int signum, pqsigfunc handler)
Definition: signal.c:180
bool filter_by_xid_enabled
Definition: pg_waldump.c:65
bool bkp_details
Definition: pg_waldump.c:54
bool filter_by_rmgr[RM_MAX_ID+1]
Definition: pg_waldump.c:62
RelFileNode filter_by_relation
Definition: pg_waldump.c:66
bool filter_by_extended
Definition: pg_waldump.c:67
bool stats_per_record
Definition: pg_waldump.c:59
int already_displayed_records
Definition: pg_waldump.c:56
int stop_after_records
Definition: pg_waldump.c:55
bool filter_by_fpw
Definition: pg_waldump.c:72
bool filter_by_relation_enabled
Definition: pg_waldump.c:68
BlockNumber filter_by_relation_block
Definition: pg_waldump.c:69
bool filter_by_rmgr_enabled
Definition: pg_waldump.c:63
TransactionId filter_by_xid
Definition: pg_waldump.c:64
ForkNumber filter_by_relation_forknum
Definition: pg_waldump.c:71
bool filter_by_relation_block_enabled
Definition: pg_waldump.c:70
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)
#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest)
#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes)
#define XLogFromFileName(fname, tli, 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:418
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:1337
#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, RelFileNode::dbNode, directory, emptyRelFileNode, 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, RelFileNode::relNode, required_argument, RM_MAX_BUILTIN_ID, RmgrIdIsCustom(), set_pglocale_pgservice(), sigint_handler(), RelFileNode::spcNode, 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(), 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 149 of file pg_waldump.c.

150 {
151  int fd = -1;
152  char fpath[MAXPGPATH];
153 
154  Assert(directory != NULL);
155 
156  snprintf(fpath, MAXPGPATH, "%s/%s", directory, fname);
157  fd = open(fpath, O_RDONLY | PG_BINARY, 0);
158 
159  if (fd < 0 && errno != ENOENT)
160  pg_fatal("could not open file \"%s\": %m", fname);
161  return fd;
162 }
#define PG_BINARY
Definition: c.h:1268
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 90 of file pg_waldump.c.

91 {
92  int i;
93 
94  for (i = 0; i <= RM_MAX_BUILTIN_ID; i++)
95  {
96  printf("%s\n", GetRmgrDesc(i)->rm_name);
97  }
98 }
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 171 of file pg_waldump.c.

172 {
173  int fd = -1;
174  DIR *xldir;
175 
176  /* open file if valid filename is provided */
177  if (fname != NULL)
179 
180  /*
181  * A valid file name is not passed, so search the complete directory. If
182  * we find any file whose name is a valid WAL file name then try to open
183  * it. If we cannot open it, bail out.
184  */
185  else if ((xldir = opendir(directory)) != NULL)
186  {
187  struct dirent *xlde;
188 
189  while ((xlde = readdir(xldir)) != NULL)
190  {
191  if (IsXLogFileName(xlde->d_name))
192  {
194  fname = pg_strdup(xlde->d_name);
195  break;
196  }
197  }
198 
199  closedir(xldir);
200  }
201 
202  /* set WalSegSz if file is successfully opened */
203  if (fd >= 0)
204  {
206  int r;
207 
208  r = read(fd, buf.data, XLOG_BLCKSZ);
209  if (r == XLOG_BLCKSZ)
210  {
211  XLogLongPageHeader longhdr = (XLogLongPageHeader) buf.data;
212 
213  WalSegSz = longhdr->xlp_seg_size;
214 
216  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",
217  "WAL segment size must be a power of two between 1 MB and 1 GB, but the WAL file \"%s\" header specifies %d bytes",
218  WalSegSz),
219  fname, WalSegSz);
220  }
221  else if (r < 0)
222  pg_fatal("could not read file \"%s\": %m",
223  fname);
224  else
225  pg_fatal("could not read file \"%s\": read %d of %d",
226  fname, r, XLOG_BLCKSZ);
227  close(fd);
228  return true;
229  }
230 
231  return false;
232 }
int closedir(DIR *)
Definition: dirent.c:123
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
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
#define IsXLogFileName(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 ( int  signum)
static

Definition at line 83 of file pg_waldump.c.

84 {
85  time_to_stop = true;
86 }

References time_to_stop.

Referenced by main().

◆ split_path()

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

Definition at line 122 of file pg_waldump.c.

123 {
124  char *sep;
125 
126  /* split filepath into directory & filename */
127  sep = strrchr(path, '/');
128 
129  /* directory path */
130  if (sep != NULL)
131  {
132  *dir = pnstrdup(path, sep - path);
133  *fname = pg_strdup(sep + 1);
134  }
135  /* local directory */
136  else
137  {
138  *dir = NULL;
139  *fname = pg_strdup(path);
140  }
141 }
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1316

References pg_strdup(), and pnstrdup().

Referenced by main().

◆ usage()

static void usage ( void  )
static

Definition at line 656 of file pg_waldump.c.

657 {
658  printf(_("%s decodes and displays PostgreSQL write-ahead logs for debugging.\n\n"),
659  progname);
660  printf(_("Usage:\n"));
661  printf(_(" %s [OPTION]... [STARTSEG [ENDSEG]]\n"), progname);
662  printf(_("\nOptions:\n"));
663  printf(_(" -b, --bkp-details output detailed information about backup blocks\n"));
664  printf(_(" -B, --block=N with --relation, only show records that modify block N\n"));
665  printf(_(" -e, --end=RECPTR stop reading at WAL location RECPTR\n"));
666  printf(_(" -f, --follow keep retrying after reaching end of WAL\n"));
667  printf(_(" -F, --fork=FORK only show records that modify blocks in fork FORK;\n"
668  " valid names are main, fsm, vm, init\n"));
669  printf(_(" -n, --limit=N number of records to display\n"));
670  printf(_(" -p, --path=PATH directory in which to find log segment files or a\n"
671  " directory with a ./pg_wal that contains such files\n"
672  " (default: current directory, ./pg_wal, $PGDATA/pg_wal)\n"));
673  printf(_(" -q, --quiet do not print any output, except for errors\n"));
674  printf(_(" -r, --rmgr=RMGR only show records generated by resource manager RMGR;\n"
675  " use --rmgr=list to list valid resource manager names\n"));
676  printf(_(" -R, --relation=T/D/R only show records that modify blocks in relation T/D/R\n"));
677  printf(_(" -s, --start=RECPTR start reading at WAL location RECPTR\n"));
678  printf(_(" -t, --timeline=TLI timeline from which to read log records\n"
679  " (default: 1 or the value used in STARTSEG)\n"));
680  printf(_(" -V, --version output version information, then exit\n"));
681  printf(_(" -w, --fullpage only show records with a full page write\n"));
682  printf(_(" -x, --xid=XID only show records with transaction ID XID\n"));
683  printf(_(" -z, --stats[=record] show statistics instead of records\n"
684  " (optionally, show per-record statistics)\n"));
685  printf(_(" -?, --help show this help, then exit\n"));
686  printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
687  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
688 }
#define _(x)
Definition: elog.c:89

References _, printf, and progname.

Referenced by main().

◆ verify_directory()

static bool verify_directory ( const char *  directory)
static

Definition at line 105 of file pg_waldump.c.

106 {
107  DIR *dir = opendir(directory);
108 
109  if (dir == NULL)
110  return false;
111  closedir(dir);
112  return true;
113 }

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

Referenced by main().

◆ WALDumpCloseSegment()

static void WALDumpCloseSegment ( XLogReaderState state)
static

Definition at line 337 of file pg_waldump.c.

338 {
339  close(state->seg.ws_file);
340  /* need to check errno? */
341  state->seg.ws_file = -1;
342 }
Definition: regguts.h:318

References close.

Referenced by main().

◆ WALDumpOpenSegment()

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

Definition at line 295 of file pg_waldump.c.

297 {
298  TimeLineID tli = *tli_p;
299  char fname[MAXPGPATH];
300  int tries;
301 
302  XLogFileName(fname, tli, nextSegNo, state->segcxt.ws_segsize);
303 
304  /*
305  * In follow mode there is a short period of time after the server has
306  * written the end of the previous file before the new file is available.
307  * So we loop for 5 seconds looking for the file to appear before giving
308  * up.
309  */
310  for (tries = 0; tries < 10; tries++)
311  {
312  state->seg.ws_file = open_file_in_directory(state->segcxt.ws_dir, fname);
313  if (state->seg.ws_file >= 0)
314  return;
315  if (errno == ENOENT)
316  {
317  int save_errno = errno;
318 
319  /* File not there yet, try again */
320  pg_usleep(500 * 1000);
321 
322  errno = save_errno;
323  continue;
324  }
325  /* Any other error, fall through and fail */
326  break;
327  }
328 
329  pg_fatal("could not find file \"%s\": %m", fname);
330 }
#define XLogFileName(fname, tli, logSegNo, 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 346 of file pg_waldump.c.

348 {
349  XLogDumpPrivate *private = state->private_data;
350  int count = XLOG_BLCKSZ;
351  WALReadError errinfo;
352 
353  if (private->endptr != InvalidXLogRecPtr)
354  {
355  if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
356  count = XLOG_BLCKSZ;
357  else if (targetPagePtr + reqLen <= private->endptr)
358  count = private->endptr - targetPagePtr;
359  else
360  {
361  private->endptr_reached = true;
362  return -1;
363  }
364  }
365 
366  if (!WALRead(state, readBuff, targetPagePtr, count, private->timeline,
367  &errinfo))
368  {
369  WALOpenSegment *seg = &errinfo.wre_seg;
370  char fname[MAXPGPATH];
371 
372  XLogFileName(fname, seg->ws_tli, seg->ws_segno,
373  state->segcxt.ws_segsize);
374 
375  if (errinfo.wre_errno != 0)
376  {
377  errno = errinfo.wre_errno;
378  pg_fatal("could not read from file %s, offset %d: %m",
379  fname, errinfo.wre_off);
380  }
381  else
382  pg_fatal("could not read from file %s, offset %d: read %d of %d",
383  fname, errinfo.wre_off, errinfo.wre_read,
384  errinfo.wre_req);
385  }
386 
387  return count;
388 }
XLogSegNo ws_segno
Definition: xlogreader.h:48
TimeLineID ws_tli
Definition: xlogreader.h:49
WALOpenSegment wre_seg
Definition: xlogreader.h:386
bool WALRead(XLogReaderState *state, char *buf, XLogRecPtr startptr, Size count, TimeLineID tli, WALReadError *errinfo)
Definition: xlogreader.c:1460

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

447 {
448  const char *id;
449  const RmgrDescData *desc = GetRmgrDesc(XLogRecGetRmid(record));
450  uint32 rec_len;
451  uint32 fpi_len;
452  uint8 info = XLogRecGetInfo(record);
453  XLogRecPtr xl_prev = XLogRecGetPrev(record);
454  StringInfoData s;
455 
456  XLogRecGetLen(record, &rec_len, &fpi_len);
457 
458  printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
459  desc->rm_name,
460  rec_len, XLogRecGetTotalLen(record),
461  XLogRecGetXid(record),
462  LSN_FORMAT_ARGS(record->ReadRecPtr),
463  LSN_FORMAT_ARGS(xl_prev));
464 
465  id = desc->rm_identify(info);
466  if (id == NULL)
467  printf("desc: UNKNOWN (%x) ", info & ~XLR_INFO_MASK);
468  else
469  printf("desc: %s ", id);
470 
471  initStringInfo(&s);
472  desc->rm_desc(&s, record);
473  printf("%s", s.data);
474 
475  resetStringInfo(&s);
476  XLogRecGetBlockRefInfo(record, true, config->bkp_details, &s, NULL);
477  printf("%s", s.data);
478  pfree(s.data);
479 }
unsigned char uint8
Definition: c.h:439
void pfree(void *pointer)
Definition: mcxt.c:1175
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:408
#define XLogRecGetRmid(decoder)
Definition: xlogreader.h:409
#define XLogRecGetTotalLen(decoder)
Definition: xlogreader.h:406
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:410
#define XLogRecGetPrev(decoder)
Definition: xlogreader.h:407
#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 526 of file pg_waldump.c.

527 {
528  int ri,
529  rj;
530  uint64 total_count = 0;
531  uint64 total_rec_len = 0;
532  uint64 total_fpi_len = 0;
533  uint64 total_len = 0;
534  double rec_len_pct,
535  fpi_len_pct;
536 
537  /*
538  * Leave if no stats have been computed yet, as tracked by the end LSN.
539  */
540  if (XLogRecPtrIsInvalid(stats->endptr))
541  return;
542 
543  /*
544  * Each row shows its percentages of the total, so make a first pass to
545  * calculate column totals.
546  */
547 
548  for (ri = 0; ri <= RM_MAX_ID; ri++)
549  {
550  if (!RmgrIdIsValid(ri))
551  continue;
552 
553  total_count += stats->rmgr_stats[ri].count;
554  total_rec_len += stats->rmgr_stats[ri].rec_len;
555  total_fpi_len += stats->rmgr_stats[ri].fpi_len;
556  }
557  total_len = total_rec_len + total_fpi_len;
558 
559  printf("WAL statistics between %X/%X and %X/%X:\n",
560  LSN_FORMAT_ARGS(stats->startptr), LSN_FORMAT_ARGS(stats->endptr));
561 
562  /*
563  * 27 is strlen("Transaction/COMMIT_PREPARED"), 20 is strlen(2^64), 8 is
564  * strlen("(100.00%)")
565  */
566 
567  printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
568  "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
569  "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
570  "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
571 
572  for (ri = 0; ri <= RM_MAX_ID; ri++)
573  {
574  uint64 count,
575  rec_len,
576  fpi_len,
577  tot_len;
578  const RmgrDescData *desc;
579 
580  if (!RmgrIdIsValid(ri))
581  continue;
582 
583  desc = GetRmgrDesc(ri);
584 
585  if (!config->stats_per_record)
586  {
587  count = stats->rmgr_stats[ri].count;
588  rec_len = stats->rmgr_stats[ri].rec_len;
589  fpi_len = stats->rmgr_stats[ri].fpi_len;
590  tot_len = rec_len + fpi_len;
591 
592  if (RmgrIdIsCustom(ri) && count == 0)
593  continue;
594 
596  count, total_count, rec_len, total_rec_len,
597  fpi_len, total_fpi_len, tot_len, total_len);
598  }
599  else
600  {
601  for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
602  {
603  const char *id;
604 
605  count = stats->record_stats[ri][rj].count;
606  rec_len = stats->record_stats[ri][rj].rec_len;
607  fpi_len = stats->record_stats[ri][rj].fpi_len;
608  tot_len = rec_len + fpi_len;
609 
610  /* Skip undefined combinations and ones that didn't occur */
611  if (count == 0)
612  continue;
613 
614  /* the upper four bits in xl_info are the rmgr's */
615  id = desc->rm_identify(rj << 4);
616  if (id == NULL)
617  id = psprintf("UNKNOWN (%x)", rj << 4);
618 
619  XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
620  count, total_count, rec_len, total_rec_len,
621  fpi_len, total_fpi_len, tot_len, total_len);
622  }
623  }
624  }
625 
626  printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
627  "", "--------", "", "--------", "", "--------", "", "--------");
628 
629  /*
630  * The percentages in earlier rows were calculated against the column
631  * total, but the ones that follow are against the row total. Note that
632  * these are displayed with a % symbol to differentiate them from the
633  * earlier ones, and are thus up to 9 characters long.
634  */
635 
636  rec_len_pct = 0;
637  if (total_len != 0)
638  rec_len_pct = 100 * (double) total_rec_len / total_len;
639 
640  fpi_len_pct = 0;
641  if (total_len != 0)
642  fpi_len_pct = 100 * (double) total_fpi_len / total_len;
643 
644  printf("%-27s "
645  "%20" INT64_MODIFIER "u %-9s"
646  "%20" INT64_MODIFIER "u %-9s"
647  "%20" INT64_MODIFIER "u %-9s"
648  "%20" INT64_MODIFIER "u %-6s\n",
649  "Total", stats->count, "",
650  total_rec_len, psprintf("[%.02f%%]", rec_len_pct),
651  total_fpi_len, psprintf("[%.02f%%]", fpi_len_pct),
652  total_len, "[100%]");
653 }
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:485
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 485 of file pg_waldump.c.

490 {
491  double n_pct,
492  rec_len_pct,
493  fpi_len_pct,
494  tot_len_pct;
495 
496  n_pct = 0;
497  if (total_count != 0)
498  n_pct = 100 * (double) n / total_count;
499 
500  rec_len_pct = 0;
501  if (total_rec_len != 0)
502  rec_len_pct = 100 * (double) rec_len / total_rec_len;
503 
504  fpi_len_pct = 0;
505  if (total_fpi_len != 0)
506  fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
507 
508  tot_len_pct = 0;
509  if (total_len != 0)
510  tot_len_pct = 100 * (double) tot_len / total_len;
511 
512  printf("%-27s "
513  "%20" INT64_MODIFIER "u (%6.02f) "
514  "%20" INT64_MODIFIER "u (%6.02f) "
515  "%20" INT64_MODIFIER "u (%6.02f) "
516  "%20" INT64_MODIFIER "u (%6.02f)\n",
517  name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
518  tot_len, tot_len_pct);
519 }
const char * name
Definition: encode.c:561

References name, and printf.

Referenced by XLogDumpDisplayStats().

◆ XLogRecordHasFPW()

static bool XLogRecordHasFPW ( XLogReaderState record)
static

Definition at line 426 of file pg_waldump.c.

427 {
428  int block_id;
429 
430  for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
431  {
432  if (!XLogRecHasBlockRef(record, block_id))
433  continue;
434 
435  if (XLogRecHasBlockImage(record, block_id))
436  return true;
437  }
438 
439  return false;
440 }
#define XLogRecMaxBlockId(decoder)
Definition: xlogreader.h:416
#define XLogRecHasBlockImage(decoder, block_id)
Definition: xlogreader.h:421
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:418

References XLogRecHasBlockImage, XLogRecHasBlockRef, and XLogRecMaxBlockId.

Referenced by main().

◆ XLogRecordMatchesRelationBlock()

static bool XLogRecordMatchesRelationBlock ( XLogReaderState record,
RelFileNode  matchRnode,
BlockNumber  matchBlock,
ForkNumber  matchFork 
)
static

Definition at line 395 of file pg_waldump.c.

399 {
400  int block_id;
401 
402  for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
403  {
404  RelFileNode rnode;
405  ForkNumber forknum;
406  BlockNumber blk;
407 
408  if (!XLogRecGetBlockTagExtended(record, block_id,
409  &rnode, &forknum, &blk, NULL))
410  continue;
411 
412  if ((matchFork == InvalidForkNumber || matchFork == forknum) &&
413  (RelFileNodeEquals(matchRnode, emptyRelFileNode) ||
414  RelFileNodeEquals(matchRnode, rnode)) &&
415  (matchBlock == InvalidBlockNumber || matchBlock == blk))
416  return true;
417  }
418 
419  return false;
420 }
uint32 BlockNumber
Definition: block.h:31
#define RelFileNodeEquals(node1, node2)
Definition: relfilenode.h:88
ForkNumber
Definition: relpath.h:41
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileNode *rnode, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)
Definition: xlogreader.c:1953

References emptyRelFileNode, InvalidBlockNumber, InvalidForkNumber, RelFileNodeEquals, XLogRecGetBlockTagExtended(), and XLogRecMaxBlockId.

Referenced by main().

Variable Documentation

◆ emptyRelFileNode

const RelFileNode emptyRelFileNode = {0, 0, 0}
static

Definition at line 40 of file pg_waldump.c.

Referenced by main(), and XLogRecordMatchesRelationBlock().

◆ progname

const char* progname
static

Definition at line 35 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 38 of file pg_waldump.c.

Referenced by main(), and sigint_handler().

◆ WalSegSz

int WalSegSz
static

Definition at line 37 of file pg_waldump.c.

Referenced by main(), and search_directory().