127 sep = strrchr(path,
'/');
159 if (
fd < 0 && errno != ENOENT)
160 pg_fatal(
"could not open file \"%s\": %m", fname);
189 while ((xlde =
readdir(xldir)) != NULL)
209 if (r == XLOG_BLCKSZ)
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",
222 pg_fatal(
"could not read file \"%s\": %m",
225 pg_fatal(
"could not read file \"%s\": read %d of %d",
226 fname, r, XLOG_BLCKSZ);
286 pg_fatal(
"could not locate WAL file \"%s\"", fname);
288 pg_fatal(
"could not find any WAL file");
310 for (tries = 0; tries < 10; tries++)
313 if (
state->seg.ws_file >= 0)
317 int save_errno = errno;
329 pg_fatal(
"could not find file \"%s\": %m", fname);
341 state->seg.ws_file = -1;
350 int count = XLOG_BLCKSZ;
355 if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
357 else if (targetPagePtr + reqLen <= private->endptr)
358 count =
private->endptr - targetPagePtr;
361 private->endptr_reached =
true;
366 if (!
WALRead(
state, readBuff, targetPagePtr, count, private->timeline,
373 state->segcxt.ws_segsize);
378 pg_fatal(
"could not read from file %s, offset %d: %m",
382 pg_fatal(
"could not read from file %s, offset %d: read %d of %d",
409 &rnode, &forknum, &blk, NULL))
458 printf(
"rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
486 uint64 n, uint64 total_count,
487 uint64 rec_len, uint64 total_rec_len,
488 uint64 fpi_len, uint64 total_fpi_len,
489 uint64 tot_len, uint64 total_len)
497 if (total_count != 0)
498 n_pct = 100 * (double) n / total_count;
501 if (total_rec_len != 0)
502 rec_len_pct = 100 * (double) rec_len / total_rec_len;
505 if (total_fpi_len != 0)
506 fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
510 tot_len_pct = 100 * (double) tot_len / total_len;
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);
530 uint64 total_count = 0;
531 uint64 total_rec_len = 0;
532 uint64 total_fpi_len = 0;
533 uint64 total_len = 0;
557 total_len = total_rec_len + total_fpi_len;
559 printf(
"WAL statistics between %X/%X and %X/%X:\n",
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 "----",
"-",
"---",
"-----------",
"---",
"--------",
"---",
"-------------",
"---");
590 tot_len = rec_len + fpi_len;
596 count, total_count, rec_len, total_rec_len,
597 fpi_len, total_fpi_len, tot_len, total_len);
608 tot_len = rec_len + fpi_len;
617 id =
psprintf(
"UNKNOWN (%x)", rj << 4);
620 count, total_count, rec_len, total_rec_len,
621 fpi_len, total_fpi_len, tot_len, total_len);
626 printf(
"%-27s %20s %8s %20s %8s %20s %8s %20s\n",
627 "",
"--------",
"",
"--------",
"",
"--------",
"",
"--------");
638 rec_len_pct = 100 * (double) total_rec_len / total_len;
642 fpi_len_pct = 100 * (double) total_fpi_len / total_len;
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%]");
658 printf(
_(
"%s decodes and displays PostgreSQL write-ahead logs for debugging.\n\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);
704 static struct option long_options[] = {
738 if (strcmp(argv[1],
"--help") == 0 || strcmp(argv[1],
"-?") == 0)
743 if (strcmp(argv[1],
"--version") == 0 || strcmp(argv[1],
"-V") == 0)
745 puts(
"pg_waldump (PostgreSQL) " PG_VERSION);
754 private.timeline = 1;
757 private.endptr_reached =
false;
759 config.
quiet =
false;
773 config.
stats =
false;
786 long_options, &optindex)) != -1)
804 if (sscanf(
optarg,
"%X/%X", &xlogid, &xrecoff) != 2)
810 private.endptr = (uint64) xlogid << 32 | xrecoff;
854 if (sscanf(
optarg,
"custom%03d", &rmid) == 1)
858 pg_log_error(
"custom resource manager \"%s\" does not exist",
887 if (sscanf(
optarg,
"%u/%u/%u",
902 if (sscanf(
optarg,
"%X/%X", &xlogid, &xrecoff) != 2)
909 private.startptr = (uint64) xlogid << 32 | xrecoff;
912 if (sscanf(
optarg,
"%u", &
private.timeline) != 1)
924 pg_log_error(
"invalid transaction ID specification: \"%s\"",
935 if (strcmp(
optarg,
"record") == 0)
937 else if (strcmp(
optarg,
"rmgr") != 0)
953 pg_log_error(
"option %s requires option %s to be specified",
954 "-B/--block",
"-R/--relation");
960 pg_log_error(
"too many command-line arguments (first is \"%s\")",
970 pg_log_error(
"could not open directory \"%s\": %m", waldir);
990 pg_fatal(
"could not open directory \"%s\": %m", waldir);
996 pg_fatal(
"could not open file \"%s\"", fname);
1006 pg_log_error(
"start WAL location %X/%X is not inside file \"%s\"",
1026 pg_fatal(
"could not open file \"%s\"", fname);
1032 if (endsegno < segno)
1033 pg_fatal(
"ENDSEG %s is before STARTSEG %s",
1046 private.endptr != (segno + 1) *
WalSegSz)
1048 pg_log_error(
"end WAL location %X/%X is not inside file \"%s\"",
1073 if (!xlogreader_state)
1074 pg_fatal(
"out of memory while allocating a WAL reading processor");
1080 pg_fatal(
"could not find a valid record after %X/%X",
1088 if (first_record !=
private.startptr &&
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)),
1095 (
uint32) (first_record -
private.startptr));
1098 stats.startptr = first_record;
1112 if (!config.
follow ||
private.endptr_reached)
1148 if (config.
stats ==
true)
1151 stats.endptr = xlogreader_state->
EndRecPtr;
1171 pg_fatal(
"error in WAL record at %X/%X: %s",
#define InvalidBlockNumber
#define BlockNumberIsValid(blockNumber)
#define ngettext(s, p, n)
#define PG_TEXTDOMAIN(domain)
#define OidIsValid(objectId)
void set_pglocale_pgservice(const char *argv0, const char *app)
struct dirent * readdir(DIR *)
DIR * opendir(const char *)
char * pg_strdup(const char *in)
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
#define required_argument
#define optional_argument
Assert(fmt[strlen(fmt) - 1] !='\n')
void pg_logging_init(const char *argv0)
#define pg_log_error(...)
#define pg_log_error_hint(...)
#define pg_log_error_detail(...)
char * pnstrdup(const char *in, Size len)
void pfree(void *pointer)
PGDLLIMPORT char * optarg
static bool search_directory(const char *directory, const char *fname)
static void XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
static void WALDumpCloseSegment(XLogReaderState *state)
static void sigint_handler(int signum)
int main(int argc, char **argv)
static volatile sig_atomic_t time_to_stop
static void split_path(const char *path, char **dir, char **fname)
struct XLogDumpConfig XLogDumpConfig
static int open_file_in_directory(const char *directory, const char *fname)
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 bool XLogRecordMatchesRelationBlock(XLogReaderState *record, RelFileNode matchRnode, BlockNumber matchBlock, ForkNumber matchFork)
static bool verify_directory(const char *directory)
static void print_rmgr_list(void)
static void WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
struct XLogDumpPrivate XLogDumpPrivate
static const char * progname
static int WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff)
static const RelFileNode emptyRelFileNode
static char * identify_target_directory(char *directory, char *fname)
static bool XLogRecordHasFPW(XLogReaderState *record)
int pg_strcasecmp(const char *s1, const char *s2)
const char * get_progname(const char *argv0)
static int fd(const char *x, int i)
char * psprintf(const char *fmt,...)
#define RelFileNodeEquals(node1, node2)
ForkNumber forkname_to_number(const char *forkName)
#define RM_MAX_BUILTIN_ID
static bool RmgrIdIsCustom(int rmid)
#define RmgrIdIsValid(rmid)
const RmgrDescData * GetRmgrDesc(RmgrId rmid)
void pg_usleep(long microsec)
pqsigfunc pqsignal(int signum, pqsigfunc handler)
void resetStringInfo(StringInfo str)
void initStringInfo(StringInfo str)
const char *(* rm_identify)(uint8 info)
void(* rm_desc)(StringInfo buf, XLogReaderState *record)
bool filter_by_xid_enabled
bool filter_by_rmgr[RM_MAX_ID+1]
RelFileNode filter_by_relation
int already_displayed_records
bool filter_by_relation_enabled
BlockNumber filter_by_relation_block
bool filter_by_rmgr_enabled
TransactionId filter_by_xid
ForkNumber filter_by_relation_forknum
bool filter_by_relation_block_enabled
XLogRecStats record_stats[RM_MAX_ID+1][MAX_XLINFO_TYPES]
XLogRecStats rmgr_stats[RM_MAX_ID+1]
#define InvalidTransactionId
#define IsValidWalSegSize(size)
XLogLongPageHeaderData * XLogLongPageHeader
#define XLogSegmentOffset(xlogptr, wal_segsz_bytes)
#define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes)
#define IsXLogFileName(fname)
#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)
#define XLogRecPtrIsInvalid(r)
#define InvalidXLogRecPtr
void XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty, bool detailed_format, StringInfo buf, uint32 *fpi_len)
XLogRecord * XLogReadRecord(XLogReaderState *state, char **errormsg)
bool WALRead(XLogReaderState *state, char *buf, XLogRecPtr startptr, Size count, TimeLineID tli, WALReadError *errinfo)
void XLogReaderFree(XLogReaderState *state)
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileNode *rnode, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)
#define XLogRecGetInfo(decoder)
#define XLogRecGetRmid(decoder)
#define XLogRecGetTotalLen(decoder)
#define XLogRecGetXid(decoder)
#define XLogRecMaxBlockId(decoder)
#define XLogRecHasBlockImage(decoder, block_id)
#define XLogRecHasBlockRef(decoder, block_id)
#define XLogRecGetPrev(decoder)
void XLogRecStoreStats(XLogStats *stats, XLogReaderState *record)
void XLogRecGetLen(XLogReaderState *record, uint32 *rec_len, uint32 *fpi_len)
static const char * directory