64 #define MAX_XLINFO_TYPES 16 73 #define fatal_error(...) do { pg_log_fatal(__VA_ARGS__); exit(EXIT_FAILURE); } while(0) 113 sep = strrchr(path,
'/');
140 Assert(directory != NULL);
143 fd = open(fpath, O_RDONLY |
PG_BINARY, 0);
145 if (fd < 0 && errno != ENOENT)
146 fatal_error(
"could not open file \"%s\": %m", fname);
171 else if ((xldir =
opendir(directory)) != NULL)
175 while ((xlde =
readdir(xldir)) != NULL)
194 r =
read(fd, buf.
data, XLOG_BLCKSZ);
195 if (r == XLOG_BLCKSZ)
202 fatal_error(
ngettext(
"WAL segment size must be a power of two between 1 MB and 1 GB, but the WAL file \"%s\" header specifies %d byte",
203 "WAL segment size must be a power of two between 1 MB and 1 GB, but the WAL file \"%s\" header specifies %d bytes",
213 fatal_error(
"could not read file \"%s\": read %d of %zu",
214 fname, r, (
Size) XLOG_BLCKSZ);
242 if (directory != NULL)
263 datadir = getenv(
"PGDATA");
275 fatal_error(
"could not locate WAL file \"%s\"", fname);
299 for (tries = 0; tries < 10; tries++)
306 int save_errno = errno;
318 fatal_error(
"could not find file \"%s\": %m", fname);
339 int count = XLOG_BLCKSZ;
344 if (targetPagePtr + XLOG_BLCKSZ <= private->
endptr)
346 else if (targetPagePtr + reqLen <= private->endptr)
347 count =
private->endptr - targetPagePtr;
350 private->endptr_reached =
true;
355 if (!
WALRead(state, readBuff, targetPagePtr, count, private->timeline,
367 fatal_error(
"could not read from file %s, offset %u: %m",
371 fatal_error(
"could not read from file %s, offset %u: read %d of %zu",
395 for (block_id = 0; block_id <= record->
max_block_id; block_id++)
466 printf(
"rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
487 for (block_id = 0; block_id <= record->
max_block_id; block_id++)
494 printf(
", blkref #%u: rel %u/%u/%u fork %s blk %u",
500 printf(
", blkref #%u: rel %u/%u/%u blk %u",
509 printf(
" FPW for WAL verification");
518 for (block_id = 0; block_id <= record->
max_block_id; block_id++)
524 printf(
"\tblkref #%u: rel %u/%u/%u fork %s blk %u",
534 printf(
" (FPW%s); hole: offset: %u, length: %u, " 535 "compression saved: %u",
537 "" :
" for WAL verification",
546 printf(
" (FPW%s); hole: offset: %u, length: %u",
548 "" :
" for WAL verification",
563 uint64 n, uint64 total_count,
564 uint64 rec_len, uint64 total_rec_len,
565 uint64 fpi_len, uint64 total_fpi_len,
566 uint64 tot_len, uint64 total_len)
574 if (total_count != 0)
575 n_pct = 100 * (double) n / total_count;
578 if (total_rec_len != 0)
579 rec_len_pct = 100 * (double) rec_len / total_rec_len;
582 if (total_fpi_len != 0)
583 fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
587 tot_len_pct = 100 * (double) tot_len / total_len;
590 "%20" INT64_MODIFIER
"u (%6.02f) " 591 "%20" INT64_MODIFIER
"u (%6.02f) " 592 "%20" INT64_MODIFIER
"u (%6.02f) " 593 "%20" INT64_MODIFIER
"u (%6.02f)\n",
594 name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
595 tot_len, tot_len_pct);
607 uint64 total_count = 0;
608 uint64 total_rec_len = 0;
609 uint64 total_fpi_len = 0;
610 uint64 total_len = 0;
625 total_len = total_rec_len + total_fpi_len;
632 printf(
"%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n" 633 "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
634 "Type",
"N",
"(%)",
"Record size",
"(%)",
"FPI size",
"(%)",
"Combined size",
"(%)",
635 "----",
"-",
"---",
"-----------",
"---",
"--------",
"---",
"-------------",
"---");
650 tot_len = rec_len + fpi_len;
653 count, total_count, rec_len, total_rec_len,
654 fpi_len, total_fpi_len, tot_len, total_len);
665 tot_len = rec_len + fpi_len;
674 id =
psprintf(
"UNKNOWN (%x)", rj << 4);
677 count, total_count, rec_len, total_rec_len,
678 fpi_len, total_fpi_len, tot_len, total_len);
683 printf(
"%-27s %20s %8s %20s %8s %20s %8s %20s\n",
684 "",
"--------",
"",
"--------",
"",
"--------",
"",
"--------");
695 rec_len_pct = 100 * (double) total_rec_len / total_len;
699 fpi_len_pct = 100 * (double) total_fpi_len / total_len;
702 "%20" INT64_MODIFIER
"u %-9s" 703 "%20" INT64_MODIFIER
"u %-9s" 704 "%20" INT64_MODIFIER
"u %-9s" 705 "%20" INT64_MODIFIER
"u %-6s\n",
706 "Total", stats->
count,
"",
707 total_rec_len,
psprintf(
"[%.02f%%]", rec_len_pct),
708 total_fpi_len,
psprintf(
"[%.02f%%]", fpi_len_pct),
709 total_len,
"[100%]");
715 printf(
_(
"%s decodes and displays PostgreSQL write-ahead logs for debugging.\n\n"),
720 printf(
_(
" -b, --bkp-details output detailed information about backup blocks\n"));
721 printf(
_(
" -e, --end=RECPTR stop reading at WAL location RECPTR\n"));
722 printf(
_(
" -f, --follow keep retrying after reaching end of WAL\n"));
723 printf(
_(
" -n, --limit=N number of records to display\n"));
724 printf(
_(
" -p, --path=PATH directory in which to find log segment files or a\n" 725 " directory with a ./pg_wal that contains such files\n" 726 " (default: current directory, ./pg_wal, $PGDATA/pg_wal)\n"));
727 printf(
_(
" -q, --quiet do not print any output, except for errors\n"));
728 printf(
_(
" -r, --rmgr=RMGR only show records generated by resource manager RMGR;\n" 729 " use --rmgr=list to list valid resource manager names\n"));
730 printf(
_(
" -s, --start=RECPTR start reading at WAL location RECPTR\n"));
731 printf(
_(
" -t, --timeline=TLI timeline from which to read log records\n" 732 " (default: 1 or the value used in STARTSEG)\n"));
733 printf(
_(
" -V, --version output version information, then exit\n"));
734 printf(
_(
" -x, --xid=XID only show records with transaction ID XID\n"));
735 printf(
_(
" -z, --stats[=record] show statistics instead of records\n" 736 " (optionally, show per-record statistics)\n"));
737 printf(
_(
" -?, --help show this help, then exit\n"));
738 printf(
_(
"\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
739 printf(
_(
"%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
756 static struct option long_options[] = {
782 if (strcmp(argv[1],
"--help") == 0 || strcmp(argv[1],
"-?") == 0)
787 if (strcmp(argv[1],
"--version") == 0 || strcmp(argv[1],
"-V") == 0)
789 puts(
"pg_waldump (PostgreSQL) " PG_VERSION);
798 private.timeline = 1;
801 private.endptr_reached =
false;
803 config.
quiet =
false;
811 config.
stats =
false;
820 while ((option =
getopt_long(argc, argv,
"be:fn:p:qr:s:t:x:z",
821 long_options, &optindex)) != -1)
829 if (sscanf(
optarg,
"%X/%X", &xlogid, &xrecoff) != 2)
835 private.endptr = (uint64) xlogid << 32 | xrecoff;
881 if (sscanf(
optarg,
"%X/%X", &xlogid, &xrecoff) != 2)
883 pg_log_error(
"could not parse start WAL location \"%s\"",
888 private.startptr = (uint64) xlogid << 32 | xrecoff;
900 pg_log_error(
"could not parse \"%s\" as a transaction ID",
911 if (strcmp(
optarg,
"record") == 0)
913 else if (strcmp(
optarg,
"rmgr") != 0)
928 pg_log_error(
"too many command-line arguments (first is \"%s\")",
938 pg_log_error(
"could not open directory \"%s\": %m", waldir);
953 if (waldir == NULL && directory != NULL)
958 fatal_error(
"could not open directory \"%s\": %m", waldir);
974 pg_log_error(
"start WAL location %X/%X is not inside file \"%s\"",
985 if (optind + 1 < argc)
990 split_path(argv[optind + 1], &directory, &fname);
1000 if (endsegno < segno)
1002 argv[optind + 1], argv[optind]);
1016 pg_log_error(
"end WAL location %X/%X is not inside file \"%s\"",
1041 if (!xlogreader_state)
1045 first_record = XLogFindNextRecord(xlogreader_state,
private.
startptr);
1048 fatal_error(
"could not find a valid record after %X/%X",
1056 if (first_record !=
private.
startptr &&
1058 printf(
ngettext(
"first record is after %X/%X, at %X/%X, skipping over %u byte\n",
1059 "first record is after %X/%X, at %X/%X, skipping over %u bytes\n",
1060 (first_record -
private.
startptr)),
1071 if (!config.
follow ||
private.endptr_reached)
1092 if (config.
stats ==
true)
#define IsValidWalSegSize(size)
static void WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
static void XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
#define InvalidXLogRecPtr
int already_displayed_records
char * pnstrdup(const char *in, Size len)
static bool search_directory(const char *directory, const char *fname)
#define XLogRecHasBlockImage(decoder, block_id)
const char * get_progname(const char *argv0)
#define pg_log_error(...)
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
void pg_logging_init(const char *argv0)
char * psprintf(const char *fmt,...)
#define XLogRecHasBlockRef(decoder, block_id)
Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES]
TransactionId filter_by_xid
int pg_strcasecmp(const char *s1, const char *s2)
static char * identify_target_directory(char *directory, char *fname)
static int fd(const char *x, int i)
#define XLogRecGetTotalLen(decoder)
#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes)
XLogLongPageHeaderData * XLogLongPageHeader
Stats rmgr_stats[RM_NEXT_ID]
bool filter_by_xid_enabled
void pg_usleep(long microsec)
#define LSN_FORMAT_ARGS(lsn)
#define required_argument
void pfree(void *pointer)
XLogRecord * XLogReadRecord(XLogReaderState *state, char **errormsg)
#define IsXLogFileName(fname)
const RmgrDescData RmgrDescTable[RM_MAX_ID+1]
DIR * opendir(const char *)
#define XLogRecGetPrev(decoder)
#define XLogFromFileName(fname, tli, logSegNo, wal_segsz_bytes)
static void WALDumpCloseSegment(XLogReaderState *state)
static void XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogReaderState *record)
static void XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record)
char * pg_strdup(const char *in)
#define InvalidTransactionId
static void split_path(const char *path, char **dir, char **fname)
struct XLogDumpConfig XLogDumpConfig
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
static int WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff)
#define XLogRecGetInfo(decoder)
void initStringInfo(StringInfo str)
#define XLogRecPtrIsInvalid(r)
void XLogReaderFree(XLogReaderState *state)
bool XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileNode *rnode, ForkNumber *forknum, BlockNumber *blknum)
#define XLogRecGetXid(decoder)
#define ngettext(s, p, n)
#define PG_TEXTDOMAIN(domain)
#define BKPIMAGE_IS_COMPRESSED
#define XLogSegmentOffset(xlogptr, wal_segsz_bytes)
const char *(* rm_identify)(uint8 info)
#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest)
#define Assert(condition)
#define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes)
static const char * directory
static int open_file_in_directory(const char *directory, const char *fname)
#define optional_argument
struct dirent * readdir(DIR *)
static bool verify_directory(const char *directory)
struct XLogDumpPrivate XLogDumpPrivate
void set_pglocale_pgservice(const char *argv0, const char *app)
static const char * progname
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)
struct XLogDumpStats XLogDumpStats
bool WALRead(XLogReaderState *state, char *buf, XLogRecPtr startptr, Size count, TimeLineID tli, WALReadError *errinfo)
void(* rm_desc)(StringInfo buf, XLogReaderState *record)
#define XLogRecBlockImageApply(decoder, block_id)
static void print_rmgr_list(void)
const char *const forkNames[]
int main(int argc, char **argv)
DecodedBkpBlock blocks[XLR_MAX_BLOCK_ID+1]
#define XLogRecGetRmid(decoder)
static void XLogDumpRecordLen(XLogReaderState *record, uint32 *rec_len, uint32 *fpi_len)