PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_waldump.c File Reference
#include "postgres.h"
#include <dirent.h>
#include <limits.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 "pg_waldump.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  XLogDumpConfig
 

Macros

#define FRONTEND   1
 

Typedefs

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)
 
int open_file_in_directory (const char *directory, const char *fname)
 
static bool search_directory (const char *directory, const char *fname, int *WalSegSz)
 
static charidentify_target_directory (char *directory, char *fname, int *WalSegSz)
 
static int required_read_len (XLogDumpPrivate *private, XLogRecPtr targetPagePtr, int reqLen)
 
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 void TarWALDumpOpenSegment (XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
 
static void TarWALDumpCloseSegment (XLogReaderState *state)
 
static int TarWALDumpReadPage (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 cleanup_tmpwal_dir_atexit (void)
 
static void usage (void)
 
int main (int argc, char **argv)
 

Variables

static const charprogname
 
static volatile sig_atomic_t time_to_stop = false
 
static XLogReaderStatexlogreader_state_cleanup = NULL
 
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

Function Documentation

◆ cleanup_tmpwal_dir_atexit()

static void cleanup_tmpwal_dir_atexit ( void  )
static

Definition at line 875 of file pg_waldump.c.

876{
877 /*
878 * Before calling rmtree, we must close any open file we have in the temp
879 * directory; else rmdir fails on Windows.
880 */
884
885 if (TmpWalSegDir != NULL)
886 {
887 rmtree(TmpWalSegDir, true);
889 }
890}
char * TmpWalSegDir
static void WALDumpCloseSegment(XLogReaderState *state)
Definition pg_waldump.c:401
static XLogReaderState * xlogreader_state_cleanup
Definition pg_waldump.c:45
static int fb(int x)
bool rmtree(const char *path, bool rmtopdir)
Definition rmtree.c:50
WALOpenSegment seg
Definition xlogreader.h:271

References fb(), rmtree(), XLogReaderState::seg, TmpWalSegDir, WALDumpCloseSegment(), WALOpenSegment::ws_file, and xlogreader_state_cleanup.

Referenced by main().

◆ create_fullpage_directory()

static void create_fullpage_directory ( char path)
static

Definition at line 122 of file pg_waldump.c.

123{
124 int ret;
125
126 switch ((ret = pg_check_dir(path)))
127 {
128 case 0:
129 /* Does not exist, so create it */
130 if (pg_mkdir_p(path, pg_dir_create_mode) < 0)
131 pg_fatal("could not create directory \"%s\": %m", path);
132 break;
133 case 1:
134 /* Present and empty, so do nothing */
135 break;
136 case 2:
137 case 3:
138 case 4:
139 /* Exists and not empty */
140 pg_fatal("directory \"%s\" exists but is not empty", path);
141 break;
142 default:
143 /* Trouble accessing directory */
144 pg_fatal("could not access directory \"%s\": %m", path);
145 }
146}
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,
int WalSegSz 
)
static

Definition at line 287 of file pg_waldump.c.

288{
289 char fpath[MAXPGPATH];
290
291 if (directory != NULL)
292 {
294 return pg_strdup(directory);
295
296 /* directory / XLOGDIR */
298 if (search_directory(fpath, fname, WalSegSz))
299 return pg_strdup(fpath);
300 }
301 else
302 {
303 const char *datadir;
304
305 /* current directory */
306 if (search_directory(".", fname, WalSegSz))
307 return pg_strdup(".");
308 /* XLOGDIR */
309 if (search_directory(XLOGDIR, fname, WalSegSz))
310 return pg_strdup(XLOGDIR);
311
312 datadir = getenv("PGDATA");
313 /* $PGDATA / XLOGDIR */
314 if (datadir != NULL)
315 {
317 if (search_directory(fpath, fname, WalSegSz))
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, int *WalSegSz)
Definition pg_waldump.c:204
#define snprintf
Definition port.h:260
int WalSegSz
Definition streamutil.c:32
#define XLOGDIR
static const char * directory
Definition zic.c:648

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

Referenced by main().

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 929 of file pg_waldump.c.

930{
934 XLogDumpPrivate private;
935 XLogDumpConfig config;
936 XLogStats stats;
937 XLogRecord *record;
939 char *waldir = NULL;
940 char *errormsg;
942
943 static struct option long_options[] = {
944 {"bkp-details", no_argument, NULL, 'b'},
945 {"block", required_argument, NULL, 'B'},
946 {"end", required_argument, NULL, 'e'},
947 {"follow", no_argument, NULL, 'f'},
948 {"fork", required_argument, NULL, 'F'},
949 {"fullpage", no_argument, NULL, 'w'},
950 {"help", no_argument, NULL, '?'},
951 {"limit", required_argument, NULL, 'n'},
952 {"path", required_argument, NULL, 'p'},
953 {"quiet", no_argument, NULL, 'q'},
954 {"relation", required_argument, NULL, 'R'},
955 {"rmgr", required_argument, NULL, 'r'},
956 {"start", required_argument, NULL, 's'},
957 {"timeline", required_argument, NULL, 't'},
958 {"xid", required_argument, NULL, 'x'},
959 {"version", no_argument, NULL, 'V'},
960 {"stats", optional_argument, NULL, 'z'},
961 {"save-fullpage", required_argument, NULL, 1},
962 {NULL, 0, NULL, 0}
963 };
964
965 int option;
966 int optindex = 0;
967
968#ifndef WIN32
970#endif
971
972 pg_logging_init(argv[0]);
973 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump"));
974 progname = get_progname(argv[0]);
975
976 if (argc > 1)
977 {
978 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
979 {
980 usage();
981 exit(0);
982 }
983 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
984 {
985 puts("pg_waldump (PostgreSQL) " PG_VERSION);
986 exit(0);
987 }
988 }
989
990 memset(&private, 0, sizeof(XLogDumpPrivate));
991 memset(&config, 0, sizeof(XLogDumpConfig));
992 memset(&stats, 0, sizeof(XLogStats));
993
994 private.timeline = 1;
995 private.segsize = 0;
996 private.startptr = InvalidXLogRecPtr;
997 private.endptr = InvalidXLogRecPtr;
998 private.endptr_reached = false;
999 private.decoding_started = false;
1000 private.archive_name = NULL;
1001 private.start_segno = 0;
1002 private.end_segno = UINT64_MAX;
1003
1004 config.quiet = false;
1005 config.bkp_details = false;
1006 config.stop_after_records = -1;
1007 config.already_displayed_records = 0;
1008 config.follow = false;
1009 /* filter_by_rmgr array was zeroed by memset above */
1010 config.filter_by_rmgr_enabled = false;
1012 config.filter_by_xid_enabled = false;
1013 config.filter_by_extended = false;
1014 config.filter_by_relation_enabled = false;
1015 config.filter_by_relation_block_enabled = false;
1017 config.filter_by_fpw = false;
1018 config.save_fullpage_path = NULL;
1019 config.stats = false;
1020 config.stats_per_record = false;
1021
1022 stats.startptr = InvalidXLogRecPtr;
1023 stats.endptr = InvalidXLogRecPtr;
1024
1025 if (argc <= 1)
1026 {
1027 pg_log_error("no arguments specified");
1028 goto bad_argument;
1029 }
1030
1031 while ((option = getopt_long(argc, argv, "bB:e:fF:n:p:qr:R:s:t:wx:z",
1032 long_options, &optindex)) != -1)
1033 {
1034 switch (option)
1035 {
1036 case 'b':
1037 config.bkp_details = true;
1038 break;
1039 case 'B':
1040 if (sscanf(optarg, "%u", &config.filter_by_relation_block) != 1 ||
1042 {
1043 pg_log_error("invalid block number: \"%s\"", optarg);
1044 goto bad_argument;
1045 }
1047 config.filter_by_extended = true;
1048 break;
1049 case 'e':
1050 if (sscanf(optarg, "%X/%08X", &xlogid, &xrecoff) != 2)
1051 {
1052 pg_log_error("invalid WAL location: \"%s\"",
1053 optarg);
1054 goto bad_argument;
1055 }
1056 private.endptr = (uint64) xlogid << 32 | xrecoff;
1057 break;
1058 case 'f':
1059 config.follow = true;
1060 break;
1061 case 'F':
1064 {
1065 pg_log_error("invalid fork name: \"%s\"", optarg);
1066 goto bad_argument;
1067 }
1068 config.filter_by_extended = true;
1069 break;
1070 case 'n':
1071 if (sscanf(optarg, "%d", &config.stop_after_records) != 1)
1072 {
1073 pg_log_error("invalid value \"%s\" for option %s", optarg, "-n/--limit");
1074 goto bad_argument;
1075 }
1076 break;
1077 case 'p':
1079 break;
1080 case 'q':
1081 config.quiet = true;
1082 break;
1083 case 'r':
1084 {
1085 int rmid;
1086
1087 if (pg_strcasecmp(optarg, "list") == 0)
1088 {
1091 }
1092
1093 /*
1094 * First look for the generated name of a custom rmgr, of
1095 * the form "custom###". We accept this form, because the
1096 * custom rmgr module is not loaded, so there's no way to
1097 * know the real name. This convention should be
1098 * consistent with that in rmgrdesc.c.
1099 */
1100 if (sscanf(optarg, "custom%03d", &rmid) == 1)
1101 {
1102 if (!RmgrIdIsCustom(rmid))
1103 {
1104 pg_log_error("custom resource manager \"%s\" does not exist",
1105 optarg);
1106 goto bad_argument;
1107 }
1108 config.filter_by_rmgr[rmid] = true;
1109 config.filter_by_rmgr_enabled = true;
1110 }
1111 else
1112 {
1113 /* then look for builtin rmgrs */
1114 for (rmid = 0; rmid <= RM_MAX_BUILTIN_ID; rmid++)
1115 {
1116 if (pg_strcasecmp(optarg, GetRmgrDesc(rmid)->rm_name) == 0)
1117 {
1118 config.filter_by_rmgr[rmid] = true;
1119 config.filter_by_rmgr_enabled = true;
1120 break;
1121 }
1122 }
1123 if (rmid > RM_MAX_BUILTIN_ID)
1124 {
1125 pg_log_error("resource manager \"%s\" does not exist",
1126 optarg);
1127 goto bad_argument;
1128 }
1129 }
1130 }
1131 break;
1132 case 'R':
1133 if (sscanf(optarg, "%u/%u/%u",
1134 &config.filter_by_relation.spcOid,
1135 &config.filter_by_relation.dbOid,
1136 &config.filter_by_relation.relNumber) != 3 ||
1139 {
1140 pg_log_error("invalid relation specification: \"%s\"", optarg);
1141 pg_log_error_detail("Expecting \"tablespace OID/database OID/relation filenode\".");
1142 goto bad_argument;
1143 }
1144 config.filter_by_relation_enabled = true;
1145 config.filter_by_extended = true;
1146 break;
1147 case 's':
1148 if (sscanf(optarg, "%X/%08X", &xlogid, &xrecoff) != 2)
1149 {
1150 pg_log_error("invalid WAL location: \"%s\"",
1151 optarg);
1152 goto bad_argument;
1153 }
1154 else
1155 private.startptr = (uint64) xlogid << 32 | xrecoff;
1156 break;
1157 case 't':
1158
1159 /*
1160 * This is like option_parse_int() but needs to handle
1161 * unsigned 32-bit int. Also, we accept both decimal and
1162 * hexadecimal specifications here.
1163 */
1164 {
1165 char *endptr;
1166 unsigned long val;
1167
1168 errno = 0;
1169 val = strtoul(optarg, &endptr, 0);
1170
1171 while (*endptr != '\0' && isspace((unsigned char) *endptr))
1172 endptr++;
1173
1174 if (*endptr != '\0')
1175 {
1176 pg_log_error("invalid value \"%s\" for option %s",
1177 optarg, "-t/--timeline");
1178 goto bad_argument;
1179 }
1180
1182 {
1183 pg_log_error("%s must be in range %u..%u",
1184 "-t/--timeline", 1, UINT_MAX);
1185 goto bad_argument;
1186 }
1187
1188 private.timeline = val;
1189
1190 break;
1191 }
1192 case 'w':
1193 config.filter_by_fpw = true;
1194 break;
1195 case 'x':
1196 if (sscanf(optarg, "%u", &config.filter_by_xid) != 1)
1197 {
1198 pg_log_error("invalid transaction ID specification: \"%s\"",
1199 optarg);
1200 goto bad_argument;
1201 }
1202 config.filter_by_xid_enabled = true;
1203 break;
1204 case 'z':
1205 config.stats = true;
1206 config.stats_per_record = false;
1207 if (optarg)
1208 {
1209 if (strcmp(optarg, "record") == 0)
1210 config.stats_per_record = true;
1211 else if (strcmp(optarg, "rmgr") != 0)
1212 {
1213 pg_log_error("unrecognized value for option %s: %s",
1214 "--stats", optarg);
1215 goto bad_argument;
1216 }
1217 }
1218 break;
1219 case 1:
1221 break;
1222 default:
1223 goto bad_argument;
1224 }
1225 }
1226
1229 {
1230 pg_log_error("option %s requires option %s to be specified",
1231 "-B/--block", "-R/--relation");
1232 goto bad_argument;
1233 }
1234
1235 if ((optind + 2) < argc)
1236 {
1237 pg_log_error("too many command-line arguments (first is \"%s\")",
1238 argv[optind + 2]);
1239 goto bad_argument;
1240 }
1241
1242 if (waldir != NULL)
1243 {
1244 /* Check whether the path looks like a tar archive by its extension */
1245 if (parse_tar_compress_algorithm(waldir, &compression))
1246 {
1247 split_path(waldir, &private.archive_dir, &private.archive_name);
1248 }
1249 /* Otherwise it must be a directory */
1250 else if (!verify_directory(waldir))
1251 {
1252 pg_log_error("could not open directory \"%s\": %m", waldir);
1253 goto bad_argument;
1254 }
1255 }
1256
1257 if (config.save_fullpage_path != NULL)
1259
1260 /* parse files as start/end boundaries, extract path if not specified */
1261 if (optind < argc)
1262 {
1263 char *directory = NULL;
1264 char *fname = NULL;
1265 int fd;
1266 XLogSegNo segno;
1267
1268 /*
1269 * If a tar archive is passed using the --path option, all other
1270 * arguments become unnecessary.
1271 */
1272 if (private.archive_name)
1273 {
1274 pg_log_error("unnecessary command-line arguments specified with tar archive (first is \"%s\")",
1275 argv[optind]);
1276 goto bad_argument;
1277 }
1278
1279 split_path(argv[optind], &directory, &fname);
1280
1281 if (waldir == NULL && directory != NULL)
1282 {
1283 waldir = directory;
1284
1286 pg_fatal("could not open directory \"%s\": %m", waldir);
1287 }
1288
1289 if (fname != NULL && parse_tar_compress_algorithm(fname, &compression))
1290 {
1291 private.archive_dir = waldir;
1292 private.archive_name = fname;
1293 }
1294 else
1295 {
1296 waldir = identify_target_directory(waldir, fname, &private.segsize);
1298 if (fd < 0)
1299 pg_fatal("could not open file \"%s\"", fname);
1300 close(fd);
1301
1302 /* parse position from file */
1303 XLogFromFileName(fname, &private.timeline, &segno, private.segsize);
1304
1305 if (!XLogRecPtrIsValid(private.startptr))
1306 XLogSegNoOffsetToRecPtr(segno, 0, private.segsize, private.startptr);
1307 else if (!XLByteInSeg(private.startptr, segno, private.segsize))
1308 {
1309 pg_log_error("start WAL location %X/%08X is not inside file \"%s\"",
1310 LSN_FORMAT_ARGS(private.startptr),
1311 fname);
1312 goto bad_argument;
1313 }
1314
1315 /* no second file specified, set end position */
1316 if (!(optind + 1 < argc) && !XLogRecPtrIsValid(private.endptr))
1317 XLogSegNoOffsetToRecPtr(segno + 1, 0, private.segsize, private.endptr);
1318
1319 /* parse ENDSEG if passed */
1320 if (optind + 1 < argc)
1321 {
1323
1324 /* ignore directory, already have that */
1325 split_path(argv[optind + 1], &directory, &fname);
1326
1328 if (fd < 0)
1329 pg_fatal("could not open file \"%s\"", fname);
1330 close(fd);
1331
1332 /* parse position from file */
1333 XLogFromFileName(fname, &private.timeline, &endsegno, private.segsize);
1334
1335 if (endsegno < segno)
1336 pg_fatal("ENDSEG %s is before STARTSEG %s",
1337 argv[optind + 1], argv[optind]);
1338
1339 if (!XLogRecPtrIsValid(private.endptr))
1340 XLogSegNoOffsetToRecPtr(endsegno + 1, 0, private.segsize,
1341 private.endptr);
1342
1343 /* set segno to endsegno for check of --end */
1344 segno = endsegno;
1345 }
1346
1347 if (!XLByteInSeg(private.endptr, segno, private.segsize) &&
1348 private.endptr != (segno + 1) * private.segsize)
1349 {
1350 pg_log_error("end WAL location %X/%08X is not inside file \"%s\"",
1351 LSN_FORMAT_ARGS(private.endptr),
1352 argv[argc - 1]);
1353 goto bad_argument;
1354 }
1355 }
1356 }
1357 else if (!private.archive_name)
1358 waldir = identify_target_directory(waldir, NULL, &private.segsize);
1359
1360 /* we don't know what to print */
1361 if (!XLogRecPtrIsValid(private.startptr))
1362 {
1363 pg_log_error("no start WAL location given");
1364 goto bad_argument;
1365 }
1366
1367 /* --follow is not supported with tar archives */
1368 if (config.follow && private.archive_name)
1369 {
1370 pg_log_error("--follow is not supported when reading from a tar archive");
1371 goto bad_argument;
1372 }
1373
1374 /* done with argument parsing, do the actual work */
1375
1376 /* we have everything we need, start reading */
1377 if (private.archive_name)
1378 {
1379 /*
1380 * A NULL directory indicates that the archive file is located in the
1381 * current working directory.
1382 */
1383 if (private.archive_dir == NULL)
1384 private.archive_dir = pg_strdup(".");
1385
1386 /* Set up for reading tar file */
1387 init_archive_reader(&private, compression);
1388
1389 /* Routine to decode WAL files in tar archive */
1391 XLogReaderAllocate(private.segsize, private.archive_dir,
1392 XL_ROUTINE(.page_read = TarWALDumpReadPage,
1393 .segment_open = TarWALDumpOpenSegment,
1394 .segment_close = TarWALDumpCloseSegment),
1395 &private);
1396 }
1397 else
1398 {
1400 XLogReaderAllocate(private.segsize, waldir,
1401 XL_ROUTINE(.page_read = WALDumpReadPage,
1402 .segment_open = WALDumpOpenSegment,
1403 .segment_close = WALDumpCloseSegment),
1404 &private);
1405 }
1406
1407 if (!xlogreader_state)
1408 pg_fatal("out of memory while allocating a WAL reading processor");
1409
1410 /*
1411 * Set up atexit cleanup of temporary directory. This must happen before
1412 * archive_waldump.c could possibly create the temporary directory. Also
1413 * arm the callback to cleanup the xlogreader state.
1414 */
1417
1418 /* first find a valid recptr to start from */
1419 first_record = XLogFindNextRecord(xlogreader_state, private.startptr, &errormsg);
1420
1422 {
1423 if (errormsg)
1424 pg_fatal("could not find a valid record after %X/%08X: %s",
1425 LSN_FORMAT_ARGS(private.startptr), errormsg);
1426 else
1427 pg_fatal("could not find a valid record after %X/%08X",
1428 LSN_FORMAT_ARGS(private.startptr));
1429 }
1430
1431 /*
1432 * Display a message that we're skipping data if `from` wasn't a pointer
1433 * to the start of a record and also wasn't a pointer to the beginning of
1434 * a segment (e.g. we were used in file mode).
1435 */
1436 if (first_record != private.startptr &&
1437 XLogSegmentOffset(private.startptr, private.segsize) != 0)
1438 pg_log_info(ngettext("first record is after %X/%08X, at %X/%08X, skipping over %u byte",
1439 "first record is after %X/%08X, at %X/%08X, skipping over %u bytes",
1440 (first_record - private.startptr)),
1441 LSN_FORMAT_ARGS(private.startptr),
1443 (uint32) (first_record - private.startptr));
1444
1445 if (config.stats == true && !config.quiet)
1446 stats.startptr = first_record;
1447
1448 /* Flag indicating that the decoding loop has been entered */
1449 private.decoding_started = true;
1450
1451 for (;;)
1452 {
1453 if (time_to_stop)
1454 {
1455 /* We've been Ctrl-C'ed, so leave */
1456 break;
1457 }
1458
1459 /* try to read the next record */
1460 record = XLogReadRecord(xlogreader_state, &errormsg);
1461 if (!record)
1462 {
1463 if (!config.follow || private.endptr_reached)
1464 break;
1465 else
1466 {
1467 pg_usleep(1000000L); /* 1 second */
1468 continue;
1469 }
1470 }
1471
1472 /* apply all specified filters */
1473 if (config.filter_by_rmgr_enabled &&
1474 !config.filter_by_rmgr[record->xl_rmid])
1475 continue;
1476
1477 if (config.filter_by_xid_enabled &&
1478 config.filter_by_xid != record->xl_xid)
1479 continue;
1480
1481 /* check for extended filtering */
1482 if (config.filter_by_extended &&
1485 config.filter_by_relation :
1487 config.filter_by_relation_block_enabled ?
1488 config.filter_by_relation_block :
1490 config.filter_by_relation_forknum))
1491 continue;
1492
1494 continue;
1495
1496 /* perform any per-record work */
1497 if (!config.quiet)
1498 {
1499 if (config.stats == true)
1500 {
1502 stats.endptr = xlogreader_state->EndRecPtr;
1503 }
1504 else
1506 }
1507
1508 /* save full pages if requested */
1509 if (config.save_fullpage_path != NULL)
1511
1512 /* check whether we printed enough */
1514 if (config.stop_after_records > 0 &&
1516 break;
1517 }
1518
1519 if (config.stats == true && !config.quiet)
1520 XLogDumpDisplayStats(&config, &stats);
1521
1522 if (time_to_stop)
1523 exit(0);
1524
1525 if (errormsg)
1526 pg_fatal("error in WAL record at %X/%08X: %s",
1527 LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),
1528 errormsg);
1529
1530 /*
1531 * Disarm atexit cleanup of open WAL file; XLogReaderFree will close it,
1532 * and we don't want the atexit callback trying to touch freed memory.
1533 */
1535
1537
1538 if (private.archive_name)
1539 free_archive_reader(&private);
1540
1541 return EXIT_SUCCESS;
1542
1544 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
1545 return EXIT_FAILURE;
1546}
void free_archive_reader(XLogDumpPrivate *privateInfo)
void init_archive_reader(XLogDumpPrivate *privateInfo, pg_compress_algorithm compression)
#define InvalidBlockNumber
Definition block.h:33
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition block.h:71
#define ngettext(s, p, n)
Definition c.h:1272
#define PG_TEXTDOMAIN(domain)
Definition c.h:1305
uint64_t uint64
Definition c.h:619
uint32_t uint32
Definition c.h:618
#define OidIsValid(objectId)
Definition c.h:860
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition exec.c:430
bool parse_tar_compress_algorithm(const char *fname, pg_compress_algorithm *algorithm)
Definition compression.c:49
pg_compress_algorithm
Definition compression.h:22
@ PG_COMPRESSION_NONE
Definition compression.h:23
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition getopt_long.c:60
#define no_argument
Definition getopt_long.h:25
#define required_argument
Definition getopt_long.h:26
#define optional_argument
Definition getopt_long.h:27
long val
Definition informix.c:689
#define close(a)
Definition win32.h:12
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_info(...)
Definition logging.h:124
#define pg_log_error_detail(...)
Definition logging.h:109
PGDLLIMPORT int optind
Definition getopt.c:51
PGDLLIMPORT char * optarg
Definition getopt.c:53
static void XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
Definition pg_waldump.c:742
static void TarWALDumpCloseSegment(XLogReaderState *state)
Definition pg_waldump.c:462
static volatile sig_atomic_t time_to_stop
Definition pg_waldump.c:43
static void split_path(const char *path, char **dir, char **fname)
Definition pg_waldump.c:155
int open_file_in_directory(const char *directory, const char *fname)
Definition pg_waldump.c:182
static void cleanup_tmpwal_dir_atexit(void)
Definition pg_waldump.c:875
static char * identify_target_directory(char *directory, char *fname, int *WalSegSz)
Definition pg_waldump.c:287
static void XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record)
Definition pg_waldump.c:662
static void create_fullpage_directory(char *path)
Definition pg_waldump.c:122
static void TarWALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
Definition pg_waldump.c:451
static bool verify_directory(const char *directory)
Definition pg_waldump.c:107
static const RelFileLocator emptyRelFileLocator
Definition pg_waldump.c:47
static void print_rmgr_list(void)
Definition pg_waldump.c:92
static void WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
Definition pg_waldump.c:359
static const char * progname
Definition pg_waldump.c:41
static void usage(void)
Definition pg_waldump.c:893
static int WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff)
Definition pg_waldump.c:410
static void XLogRecordSaveFPWs(XLogReaderState *record, const char *savepath)
Definition pg_waldump.c:606
static bool XLogRecordHasFPW(XLogReaderState *record)
Definition pg_waldump.c:585
static int TarWALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff)
Definition pg_waldump.c:474
static void sigint_handler(SIGNAL_ARGS)
Definition pg_waldump.c:85
static bool XLogRecordMatchesRelationBlock(XLogReaderState *record, RelFileLocator matchRlocator, BlockNumber matchBlock, ForkNumber matchFork)
Definition pg_waldump.c:554
#define pqsignal
Definition port.h:547
int pg_strcasecmp(const char *s1, const char *s2)
const char * get_progname(const char *argv0)
Definition path.c:652
static int fd(const char *x, int i)
ForkNumber forkname_to_number(const char *forkName)
Definition relpath.c:50
@ InvalidForkNumber
Definition relpath.h:57
#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:193
#define EXIT_FAILURE
Definition settings.h:197
void pg_usleep(long microsec)
Definition signal.c:53
RelFileNumber relNumber
bool filter_by_xid_enabled
Definition pg_waldump.c:64
RelFileLocator filter_by_relation
Definition pg_waldump.c:65
char * save_fullpage_path
Definition pg_waldump.c:74
bool filter_by_rmgr[RM_MAX_ID+1]
Definition pg_waldump.c:61
bool filter_by_extended
Definition pg_waldump.c:66
bool stats_per_record
Definition pg_waldump.c:58
int already_displayed_records
Definition pg_waldump.c:55
int stop_after_records
Definition pg_waldump.c:54
bool filter_by_relation_enabled
Definition pg_waldump.c:67
BlockNumber filter_by_relation_block
Definition pg_waldump.c:68
bool filter_by_rmgr_enabled
Definition pg_waldump.c:62
TransactionId filter_by_xid
Definition pg_waldump.c:63
ForkNumber filter_by_relation_forknum
Definition pg_waldump.c:70
bool filter_by_relation_block_enabled
Definition pg_waldump.c:69
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 XLogRecPtrIsValid(r)
Definition xlogdefs.h:29
#define LSN_FORMAT_ARGS(lsn)
Definition xlogdefs.h:47
uint64 XLogRecPtr
Definition xlogdefs.h:21
#define InvalidXLogRecPtr
Definition xlogdefs.h:28
uint64 XLogSegNo
Definition xlogdefs.h:52
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition xlogreader.c:108
XLogRecord * XLogReadRecord(XLogReaderState *state, char **errormsg)
Definition xlogreader.c:391
void XLogReaderFree(XLogReaderState *state)
Definition xlogreader.c:163
XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
#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(), cleanup_tmpwal_dir_atexit(), close, create_fullpage_directory(), RelFileLocator::dbOid, directory, emptyRelFileLocator, EXIT_FAILURE, EXIT_SUCCESS, fb(), 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(), free_archive_reader(), get_progname(), getopt_long(), GetRmgrDesc(), identify_target_directory(), init_archive_reader(), InvalidBlockNumber, InvalidForkNumber, InvalidTransactionId, InvalidXLogRecPtr, LSN_FORMAT_ARGS, ngettext, no_argument, OidIsValid, open_file_in_directory(), optarg, optind, optional_argument, parse_tar_compress_algorithm(), PG_COMPRESSION_NONE, pg_fatal, pg_log_error, pg_log_error_detail, pg_log_error_hint, pg_log_info, pg_logging_init(), pg_strcasecmp(), pg_strdup(), PG_TEXTDOMAIN, pg_usleep(), pqsignal, print_rmgr_list(), progname, XLogDumpConfig::quiet, 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, TarWALDumpCloseSegment(), TarWALDumpOpenSegment(), TarWALDumpReadPage(), time_to_stop, usage(), val, verify_directory(), WALDumpCloseSegment(), WALDumpOpenSegment(), WALDumpReadPage(), XLogRecord::xl_rmid, XL_ROUTINE, XLogRecord::xl_xid, XLByteInSeg, XLogDumpDisplayRecord(), XLogDumpDisplayStats(), XLogFindNextRecord(), XLogFromFileName(), xlogreader_state_cleanup, XLogReaderAllocate(), XLogReaderFree(), XLogReadRecord(), XLogRecordHasFPW(), XLogRecordMatchesRelationBlock(), XLogRecordSaveFPWs(), XLogRecPtrIsValid, XLogRecStoreStats(), XLogSegmentOffset, and XLogSegNoOffsetToRecPtr.

◆ open_file_in_directory()

int open_file_in_directory ( const char directory,
const char fname 
)

Definition at line 182 of file pg_waldump.c.

183{
184 int fd = -1;
185 char fpath[MAXPGPATH];
186
188
189 snprintf(fpath, MAXPGPATH, "%s/%s", directory, fname);
190 fd = open(fpath, O_RDONLY | PG_BINARY, 0);
191
192 if (fd < 0 && errno != ENOENT)
193 pg_fatal("could not open file \"%s\": %m", fname);
194 return fd;
195}
#define Assert(condition)
Definition c.h:945
#define PG_BINARY
Definition c.h:1376

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

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

◆ print_rmgr_list()

static void print_rmgr_list ( void  )
static

Definition at line 92 of file pg_waldump.c.

93{
94 int i;
95
96 for (i = 0; i <= RM_MAX_BUILTIN_ID; i++)
97 {
98 printf("%s\n", GetRmgrDesc(i)->rm_name);
99 }
100}
int i
Definition isn.c:77
#define printf(...)
Definition port.h:266

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

Referenced by main().

◆ required_read_len()

static int required_read_len ( XLogDumpPrivate private,
XLogRecPtr  targetPagePtr,
int  reqLen 
)
inlinestatic

Definition at line 336 of file pg_waldump.c.

338{
339 int count = XLOG_BLCKSZ;
340
341 if (XLogRecPtrIsValid(private->endptr))
342 {
344 count = XLOG_BLCKSZ;
345 else if (targetPagePtr + reqLen <= private->endptr)
346 count = private->endptr - targetPagePtr;
347 else
348 {
349 private->endptr_reached = true;
350 return -1;
351 }
352 }
353
354 return count;
355}

References fb(), and XLogRecPtrIsValid.

Referenced by TarWALDumpReadPage(), and WALDumpReadPage().

◆ search_directory()

static bool search_directory ( const char directory,
const char fname,
int WalSegSz 
)
static

Definition at line 204 of file pg_waldump.c.

205{
206 int fd = -1;
207 DIR *xldir;
208
209 /* open file if valid filename is provided */
210 if (fname != NULL)
212
213 /*
214 * A valid file name is not passed, so search the complete directory. If
215 * we find any file whose name is a valid WAL file name then try to open
216 * it. If we cannot open it, bail out.
217 */
218 else if ((xldir = opendir(directory)) != NULL)
219 {
220 struct dirent *xlde;
221
222 while ((xlde = readdir(xldir)) != NULL)
223 {
224 if (IsXLogFileName(xlde->d_name))
225 {
227 fname = pg_strdup(xlde->d_name);
228 break;
229 }
230 }
231
233 }
234
235 /* set WalSegSz if file is successfully opened */
236 if (fd >= 0)
237 {
239 int r;
240
241 r = read(fd, buf.data, XLOG_BLCKSZ);
242 if (r == XLOG_BLCKSZ)
243 {
245
246 if (!IsValidWalSegSize(longhdr->xlp_seg_size))
247 {
248 pg_log_error(ngettext("invalid WAL segment size in WAL file \"%s\" (%d byte)",
249 "invalid WAL segment size in WAL file \"%s\" (%d bytes)",
250 longhdr->xlp_seg_size),
251 fname, longhdr->xlp_seg_size);
252 pg_log_error_detail("The WAL segment size must be a power of two between 1 MB and 1 GB.");
253 exit(1);
254 }
255
256 *WalSegSz = longhdr->xlp_seg_size;
257 }
258 else if (r < 0)
259 pg_fatal("could not read file \"%s\": %m",
260 fname);
261 else
262 pg_fatal("could not read file \"%s\": read %d of %d",
263 fname, r, XLOG_BLCKSZ);
264 close(fd);
265 return true;
266 }
267
268 return false;
269}
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
static char buf[DEFAULT_XLOG_SEG_SIZE]
Definition dirent.c:26
#define IsValidWalSegSize(size)
XLogLongPageHeaderData * XLogLongPageHeader
static bool IsXLogFileName(const char *fname)

References buf, close, closedir(), directory, fb(), fd(), IsValidWalSegSize, IsXLogFileName(), ngettext, open_file_in_directory(), opendir(), pg_fatal, pg_log_error, pg_log_error_detail, pg_strdup(), read, readdir(), and WalSegSz.

Referenced by identify_target_directory().

◆ sigint_handler()

static void sigint_handler ( SIGNAL_ARGS  )
static

Definition at line 85 of file pg_waldump.c.

86{
87 time_to_stop = true;
88}

References time_to_stop.

Referenced by main().

◆ split_path()

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

Definition at line 155 of file pg_waldump.c.

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

References fb(), pg_strdup(), and pnstrdup().

Referenced by main().

◆ TarWALDumpCloseSegment()

static void TarWALDumpCloseSegment ( XLogReaderState state)
static

Definition at line 462 of file pg_waldump.c.

463{
464 close(state->seg.ws_file);
465 /* need to check errno? */
466 state->seg.ws_file = -1;
467}

References close.

Referenced by main().

◆ TarWALDumpOpenSegment()

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

Definition at line 451 of file pg_waldump.c.

453{
454 /* No action needed */
455}

Referenced by main().

◆ TarWALDumpReadPage()

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

Definition at line 474 of file pg_waldump.c.

476{
477 XLogDumpPrivate *private = state->private_data;
478 int count = required_read_len(private, targetPagePtr, reqLen);
479 int segsize = state->segcxt.ws_segsize;
481
482 /* Bail out if the end of the requested range has already been reached */
483 if (count < 0)
484 return -1;
485
486 /*
487 * If the target page is in a different segment, release the hash entry
488 * buffer and remove any spilled temporary file for the previous segment.
489 * Since pg_waldump never requests the same WAL bytes twice, moving to a
490 * new segment means the previous segment's data will not be needed again.
491 *
492 * Afterward, check whether the next required WAL segment was already
493 * spilled to the temporary directory before invoking the archive
494 * streamer.
495 */
496 curSegNo = state->seg.ws_segno;
497 if (!XLByteInSeg(targetPagePtr, curSegNo, segsize))
498 {
499 char fname[MAXFNAMELEN];
501
502 /*
503 * Calculate the next WAL segment to be decoded from the given page
504 * pointer.
505 */
507 state->seg.ws_tli = private->timeline;
508 state->seg.ws_segno = nextSegNo;
509
510 /* Close the WAL segment file if it is currently open */
511 if (state->seg.ws_file >= 0)
512 {
513 close(state->seg.ws_file);
514 state->seg.ws_file = -1;
515 }
516
517 /*
518 * If in pre-reading mode (prior to actual decoding), do not delete
519 * any entries that might be requested again once the decoding loop
520 * starts. For more details, see the comments in
521 * read_archive_wal_page().
522 */
523 if (private->decoding_started && curSegNo < nextSegNo)
524 {
525 XLogFileName(fname, state->seg.ws_tli, curSegNo, segsize);
526 free_archive_wal_entry(fname, private);
527 }
528
529 /*
530 * If the next segment exists in the temporary spill directory, open
531 * it and continue reading from there.
532 */
533 if (TmpWalSegDir != NULL)
534 {
535 XLogFileName(fname, state->seg.ws_tli, nextSegNo, segsize);
536 state->seg.ws_file = open_file_in_directory(TmpWalSegDir, fname);
537 }
538 }
539
540 /* Continue reading from the open WAL segment, if any */
541 if (state->seg.ws_file >= 0)
543 readBuff);
544
545 /* Otherwise, read the WAL page from the archive streamer */
546 return read_archive_wal_page(private, targetPagePtr, count, readBuff);
547}
int read_archive_wal_page(XLogDumpPrivate *privateInfo, XLogRecPtr targetPagePtr, Size count, char *readBuff)
void free_archive_wal_entry(const char *fname, XLogDumpPrivate *privateInfo)
static int required_read_len(XLogDumpPrivate *private, XLogRecPtr targetPagePtr, int reqLen)
Definition pg_waldump.c:336
#define MAXFNAMELEN
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes)
static void XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)

References close, fb(), free_archive_wal_entry(), MAXFNAMELEN, open_file_in_directory(), read_archive_wal_page(), required_read_len(), TmpWalSegDir, WALDumpReadPage(), XLByteInSeg, XLByteToSeg, and XLogFileName().

Referenced by main().

◆ usage()

static void usage ( void  )
static

Definition at line 893 of file pg_waldump.c.

894{
895 printf(_("%s decodes and displays PostgreSQL write-ahead logs for debugging.\n\n"),
896 progname);
897 printf(_("Usage:\n"));
898 printf(_(" %s [OPTION]... [STARTSEG [ENDSEG]]\n"), progname);
899 printf(_("\nOptions:\n"));
900 printf(_(" -b, --bkp-details output detailed information about backup blocks\n"));
901 printf(_(" -B, --block=N with --relation, only show records that modify block N\n"));
902 printf(_(" -e, --end=RECPTR stop reading at WAL location RECPTR\n"));
903 printf(_(" -f, --follow keep retrying after reaching end of WAL\n"));
904 printf(_(" -F, --fork=FORK only show records that modify blocks in fork FORK;\n"
905 " valid names are main, fsm, vm, init\n"));
906 printf(_(" -n, --limit=N number of records to display\n"));
907 printf(_(" -p, --path=PATH a tar archive or a directory in which to find WAL segment files or\n"
908 " a directory with a pg_wal subdirectory containing such files\n"
909 " (default: current directory, ./pg_wal, $PGDATA/pg_wal)\n"));
910 printf(_(" -q, --quiet do not print any output, except for errors\n"));
911 printf(_(" -r, --rmgr=RMGR only show records generated by resource manager RMGR;\n"
912 " use --rmgr=list to list valid resource manager names\n"));
913 printf(_(" -R, --relation=T/D/R only show records that modify blocks in relation T/D/R\n"));
914 printf(_(" -s, --start=RECPTR start reading at WAL location RECPTR\n"));
915 printf(_(" -t, --timeline=TLI timeline from which to read WAL records\n"
916 " (default: 1 or the value used in STARTSEG)\n"));
917 printf(_(" -V, --version output version information, then exit\n"));
918 printf(_(" -w, --fullpage only show records with a full page write\n"));
919 printf(_(" -x, --xid=XID only show records with transaction ID XID\n"));
920 printf(_(" -z, --stats[=record] show statistics instead of records\n"
921 " (optionally, show per-record statistics)\n"));
922 printf(_(" --save-fullpage=DIR save full page images to DIR\n"));
923 printf(_(" -?, --help show this help, then exit\n"));
924 printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
925 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
926}
#define _(x)
Definition elog.c:95

References _, fb(), printf, and progname.

Referenced by main().

◆ verify_directory()

static bool verify_directory ( const char directory)
static

Definition at line 107 of file pg_waldump.c.

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

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

Referenced by main().

◆ WALDumpCloseSegment()

static void WALDumpCloseSegment ( XLogReaderState state)
static

Definition at line 401 of file pg_waldump.c.

402{
403 close(state->seg.ws_file);
404 /* need to check errno? */
405 state->seg.ws_file = -1;
406}

References close.

Referenced by cleanup_tmpwal_dir_atexit(), and main().

◆ WALDumpOpenSegment()

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

Definition at line 359 of file pg_waldump.c.

361{
362 TimeLineID tli = *tli_p;
363 char fname[MAXPGPATH];
364 int tries;
365
366 XLogFileName(fname, tli, nextSegNo, state->segcxt.ws_segsize);
367
368 /*
369 * In follow mode there is a short period of time after the server has
370 * written the end of the previous file before the new file is available.
371 * So we loop for 5 seconds looking for the file to appear before giving
372 * up.
373 */
374 for (tries = 0; tries < 10; tries++)
375 {
376 state->seg.ws_file = open_file_in_directory(state->segcxt.ws_dir, fname);
377 if (state->seg.ws_file >= 0)
378 return;
379 if (errno == ENOENT)
380 {
381 int save_errno = errno;
382
383 /* File not there yet, try again */
384 pg_usleep(500 * 1000);
385
387 continue;
388 }
389 /* Any other error, fall through and fail */
390 break;
391 }
392
393 pg_fatal("could not find file \"%s\": %m", fname);
394}
uint32 TimeLineID
Definition xlogdefs.h:63

References fb(), 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 410 of file pg_waldump.c.

412{
413 XLogDumpPrivate *private = state->private_data;
414 int count = required_read_len(private, targetPagePtr, reqLen);
416
417 /* Bail out if the end of the requested range has already been reached */
418 if (count < 0)
419 return -1;
420
421 if (!WALRead(state, readBuff, targetPagePtr, count, private->timeline,
422 &errinfo))
423 {
424 WALOpenSegment *seg = &errinfo.wre_seg;
425 char fname[MAXPGPATH];
426
427 XLogFileName(fname, seg->ws_tli, seg->ws_segno,
428 state->segcxt.ws_segsize);
429
430 if (errinfo.wre_errno != 0)
431 {
432 errno = errinfo.wre_errno;
433 pg_fatal("could not read from file \"%s\", offset %d: %m",
434 fname, errinfo.wre_off);
435 }
436 else
437 pg_fatal("could not read from file \"%s\", offset %d: read %d of %d",
438 fname, errinfo.wre_off, errinfo.wre_read,
439 errinfo.wre_req);
440 }
441
442 return count;
443}
XLogSegNo ws_segno
Definition xlogreader.h:48
TimeLineID ws_tli
Definition xlogreader.h:49
bool WALRead(XLogReaderState *state, char *buf, XLogRecPtr startptr, Size count, TimeLineID tli, WALReadError *errinfo)

References fb(), MAXPGPATH, pg_fatal, required_read_len(), WALRead(), WALOpenSegment::ws_segno, WALOpenSegment::ws_tli, and XLogFileName().

Referenced by main(), and TarWALDumpReadPage().

◆ XLogDumpDisplayRecord()

static void XLogDumpDisplayRecord ( XLogDumpConfig config,
XLogReaderState record 
)
static

Definition at line 662 of file pg_waldump.c.

663{
664 const char *id;
665 const RmgrDescData *desc = GetRmgrDesc(XLogRecGetRmid(record));
666 uint32 rec_len;
667 uint32 fpi_len;
668 uint8 info = XLogRecGetInfo(record);
669 XLogRecPtr xl_prev = XLogRecGetPrev(record);
671
672 XLogRecGetLen(record, &rec_len, &fpi_len);
673
674 printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
675 desc->rm_name,
676 rec_len, XLogRecGetTotalLen(record),
677 XLogRecGetXid(record),
679 LSN_FORMAT_ARGS(xl_prev));
680
681 id = desc->rm_identify(info);
682 if (id == NULL)
683 printf("desc: UNKNOWN (%x) ", info & ~XLR_INFO_MASK);
684 else
685 printf("desc: %s ", id);
686
687 initStringInfo(&s);
688 desc->rm_desc(&s, record);
689 printf("%s", s.data);
690
691 resetStringInfo(&s);
692 XLogRecGetBlockRefInfo(record, true, config->bkp_details, &s, NULL);
693 printf("%s", s.data);
694 pfree(s.data);
695}
uint8_t uint8
Definition c.h:616
void pfree(void *pointer)
Definition mcxt.c:1616
void resetStringInfo(StringInfo str)
Definition stringinfo.c:126
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
const char * rm_name
Definition rmgrdesc.h:16
void(* rm_desc)(StringInfo buf, XLogReaderState *record)
Definition rmgrdesc.h:17
const char *(* rm_identify)(uint8 info)
Definition rmgrdesc.h:18
XLogRecPtr ReadRecPtr
Definition xlogreader.h:205
void XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty, bool detailed_format, StringInfo buf, uint32 *fpi_len)
Definition xlogdesc.c:249
#define XLogRecGetInfo(decoder)
Definition xlogreader.h:410
#define XLogRecGetRmid(decoder)
Definition xlogreader.h:411
#define XLogRecGetTotalLen(decoder)
Definition xlogreader.h:408
#define XLogRecGetXid(decoder)
Definition xlogreader.h:412
#define XLogRecGetPrev(decoder)
Definition xlogreader.h:409
#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, fb(), 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 742 of file pg_waldump.c.

743{
744 int ri,
745 rj;
749 uint64 total_len = 0;
750 double rec_len_pct,
752
753 /*
754 * Leave if no stats have been computed yet, as tracked by the end LSN.
755 */
756 if (!XLogRecPtrIsValid(stats->endptr))
757 return;
758
759 /*
760 * Each row shows its percentages of the total, so make a first pass to
761 * calculate column totals.
762 */
763
764 for (ri = 0; ri <= RM_MAX_ID; ri++)
765 {
766 if (!RmgrIdIsValid(ri))
767 continue;
768
769 total_count += stats->rmgr_stats[ri].count;
772 }
773 total_len = total_rec_len + total_fpi_len;
774
775 printf("WAL statistics between %X/%08X and %X/%08X:\n",
776 LSN_FORMAT_ARGS(stats->startptr), LSN_FORMAT_ARGS(stats->endptr));
777
778 /*
779 * 27 is strlen("Transaction/COMMIT_PREPARED"), 20 is strlen(2^64), 8 is
780 * strlen("(100.00%)")
781 */
782
783 printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
784 "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
785 "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
786 "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
787
788 for (ri = 0; ri <= RM_MAX_ID; ri++)
789 {
790 uint64 count,
791 rec_len,
792 fpi_len,
793 tot_len;
794 const RmgrDescData *desc;
795
796 if (!RmgrIdIsValid(ri))
797 continue;
798
799 desc = GetRmgrDesc(ri);
800
801 if (!config->stats_per_record)
802 {
803 count = stats->rmgr_stats[ri].count;
804 rec_len = stats->rmgr_stats[ri].rec_len;
805 fpi_len = stats->rmgr_stats[ri].fpi_len;
806 tot_len = rec_len + fpi_len;
807
808 if (RmgrIdIsCustom(ri) && count == 0)
809 continue;
810
812 count, total_count, rec_len, total_rec_len,
813 fpi_len, total_fpi_len, tot_len, total_len);
814 }
815 else
816 {
817 for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
818 {
819 const char *id;
820
821 count = stats->record_stats[ri][rj].count;
822 rec_len = stats->record_stats[ri][rj].rec_len;
823 fpi_len = stats->record_stats[ri][rj].fpi_len;
824 tot_len = rec_len + fpi_len;
825
826 /* Skip undefined combinations and ones that didn't occur */
827 if (count == 0)
828 continue;
829
830 /* the upper four bits in xl_info are the rmgr's */
831 id = desc->rm_identify(rj << 4);
832 if (id == NULL)
833 id = psprintf("UNKNOWN (%x)", rj << 4);
834
835 XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
836 count, total_count, rec_len, total_rec_len,
837 fpi_len, total_fpi_len, tot_len, total_len);
838 }
839 }
840 }
841
842 printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
843 "", "--------", "", "--------", "", "--------", "", "--------");
844
845 /*
846 * The percentages in earlier rows were calculated against the column
847 * total, but the ones that follow are against the row total. Note that
848 * these are displayed with a % symbol to differentiate them from the
849 * earlier ones, and are thus up to 9 characters long.
850 */
851
852 rec_len_pct = 0;
853 if (total_len != 0)
854 rec_len_pct = 100 * (double) total_rec_len / total_len;
855
856 fpi_len_pct = 0;
857 if (total_len != 0)
858 fpi_len_pct = 100 * (double) total_fpi_len / total_len;
859
860 printf("%-27s "
861 "%20" PRIu64 " %-9s"
862 "%20" PRIu64 " %-9s"
863 "%20" PRIu64 " %-9s"
864 "%20" PRIu64 " %-6s\n",
865 "Total", stats->count, "",
866 total_rec_len, psprintf("[%.02f%%]", rec_len_pct),
867 total_fpi_len, psprintf("[%.02f%%]", fpi_len_pct),
868 total_len, "[100%]");
869}
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:701
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
#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, fb(), 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 XLogRecPtrIsValid.

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

706{
707 double n_pct,
711
712 n_pct = 0;
713 if (total_count != 0)
714 n_pct = 100 * (double) n / total_count;
715
716 rec_len_pct = 0;
717 if (total_rec_len != 0)
718 rec_len_pct = 100 * (double) rec_len / total_rec_len;
719
720 fpi_len_pct = 0;
721 if (total_fpi_len != 0)
722 fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
723
724 tot_len_pct = 0;
725 if (total_len != 0)
726 tot_len_pct = 100 * (double) tot_len / total_len;
727
728 printf("%-27s "
729 "%20" PRIu64 " (%6.02f) "
730 "%20" PRIu64 " (%6.02f) "
731 "%20" PRIu64 " (%6.02f) "
732 "%20" PRIu64 " (%6.02f)\n",
733 name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
735}
const char * name

References fb(), name, and printf.

Referenced by XLogDumpDisplayStats().

◆ XLogRecordHasFPW()

static bool XLogRecordHasFPW ( XLogReaderState record)
static

Definition at line 585 of file pg_waldump.c.

586{
587 int block_id;
588
589 for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
590 {
591 if (!XLogRecHasBlockRef(record, block_id))
592 continue;
593
594 if (XLogRecHasBlockImage(record, block_id))
595 return true;
596 }
597
598 return false;
599}
#define XLogRecMaxBlockId(decoder)
Definition xlogreader.h:418
#define XLogRecHasBlockImage(decoder, block_id)
Definition xlogreader.h:423
#define XLogRecHasBlockRef(decoder, block_id)
Definition xlogreader.h:420

References fb(), XLogRecHasBlockImage, XLogRecHasBlockRef, and XLogRecMaxBlockId.

Referenced by main().

◆ XLogRecordMatchesRelationBlock()

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

Definition at line 554 of file pg_waldump.c.

558{
559 int block_id;
560
561 for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
562 {
563 RelFileLocator rlocator;
564 ForkNumber forknum;
566
568 &rlocator, &forknum, &blk, NULL))
569 continue;
570
571 if ((matchFork == InvalidForkNumber || matchFork == forknum) &&
575 return true;
576 }
577
578 return false;
579}
uint32 BlockNumber
Definition block.h:31
#define RelFileLocatorEquals(locator1, locator2)
ForkNumber
Definition relpath.h:56
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)

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

Referenced by main().

◆ XLogRecordSaveFPWs()

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

Definition at line 606 of file pg_waldump.c.

607{
608 int block_id;
609
610 for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
611 {
613 Page page;
614 char filename[MAXPGPATH];
615 char forkname[FORKNAMECHARS + 2]; /* _ + terminating zero */
616 FILE *file;
620
621 if (!XLogRecHasBlockRef(record, block_id))
622 continue;
623
624 if (!XLogRecHasBlockImage(record, block_id))
625 continue;
626
627 page = (Page) buf.data;
628
629 /* Full page exists, so let's save it */
630 if (!RestoreBlockImage(record, block_id, page))
631 pg_fatal("%s", record->errormsg_buf);
632
634 &rnode, &fork, &blk, NULL);
635
636 if (fork >= 0 && fork <= MAX_FORKNUM)
637 sprintf(forkname, "_%s", forkNames[fork]);
638 else
639 pg_fatal("invalid fork number: %u", fork);
640
641 snprintf(filename, MAXPGPATH, "%s/%08X-%08X-%08X.%u.%u.%u.%u%s", savepath,
642 record->seg.ws_tli,
644 rnode.spcOid, rnode.dbOid, rnode.relNumber, blk, forkname);
645
646 file = fopen(filename, PG_BINARY_W);
647 if (!file)
648 pg_fatal("could not open file \"%s\": %m", filename);
649
650 if (fwrite(page, BLCKSZ, 1, file) != 1)
651 pg_fatal("could not write file \"%s\": %m", filename);
652
653 if (fclose(file) != 0)
654 pg_fatal("could not close file \"%s\": %m", filename);
655 }
656}
PageData * Page
Definition bufpage.h:81
#define PG_BINARY_W
Definition c.h:1379
static char * filename
Definition pg_dumpall.c:133
#define sprintf
Definition port.h:262
const char *const forkNames[]
Definition relpath.c:33
#define MAX_FORKNUM
Definition relpath.h:70
#define FORKNAMECHARS
Definition relpath.h:72
char * errormsg_buf
Definition xlogreader.h:310
bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)

References buf, XLogReaderState::errormsg_buf, fb(), filename, FORKNAMECHARS, forkNames, LSN_FORMAT_ARGS, MAX_FORKNUM, MAXPGPATH, PG_BINARY_W, pg_fatal, XLogReaderState::ReadRecPtr, RestoreBlockImage(), XLogReaderState::seg, snprintf, sprintf, WALOpenSegment::ws_tli, XLogRecGetBlockTagExtended(), XLogRecHasBlockImage, XLogRecHasBlockRef, and XLogRecMaxBlockId.

Referenced by main().

Variable Documentation

◆ emptyRelFileLocator

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

Definition at line 47 of file pg_waldump.c.

47{0, 0, 0};

Referenced by main(), and XLogRecordMatchesRelationBlock().

◆ progname

const char* progname
static

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

Referenced by main(), and sigint_handler().

◆ xlogreader_state_cleanup

XLogReaderState* xlogreader_state_cleanup = NULL
static

Definition at line 45 of file pg_waldump.c.

Referenced by cleanup_tmpwal_dir_atexit(), and main().