137 pg_fatal(
"could not create directory \"%s\": %m", path);
146 pg_fatal(
"directory \"%s\" exists but is not empty", path);
150 pg_fatal(
"could not access directory \"%s\": %m", path);
166 sep = strrchr(path,
'/');
198 if (
fd < 0 && errno != ENOENT)
199 pg_fatal(
"could not open file \"%s\": %m", fname);
228 while ((xlde =
readdir(xldir)) != NULL)
248 if (r == XLOG_BLCKSZ)
255 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",
256 "WAL segment size must be a power of two between 1 MB and 1 GB, but the WAL file \"%s\" header specifies %d bytes",
261 pg_fatal(
"could not read file \"%s\": %m",
264 pg_fatal(
"could not read file \"%s\": read %d of %d",
265 fname, r, XLOG_BLCKSZ);
325 pg_fatal(
"could not locate WAL file \"%s\"", fname);
327 pg_fatal(
"could not find any WAL file");
349 for (tries = 0; tries < 10; tries++)
352 if (
state->seg.ws_file >= 0)
356 int save_errno = errno;
368 pg_fatal(
"could not find file \"%s\": %m", fname);
380 state->seg.ws_file = -1;
389 int count = XLOG_BLCKSZ;
394 if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
396 else if (targetPagePtr + reqLen <= private->endptr)
397 count =
private->endptr - targetPagePtr;
400 private->endptr_reached =
true;
405 if (!
WALRead(
state, readBuff, targetPagePtr, count, private->timeline,
412 state->segcxt.ws_segsize);
417 pg_fatal(
"could not read from file %s, offset %d: %m",
421 pg_fatal(
"could not read from file %s, offset %d: read %d of %d",
448 &rlocator, &forknum, &blk, NULL))
514 &rnode, &fork, &blk, NULL);
519 pg_fatal(
"invalid fork number: %u", fork);
529 if (fwrite(page, BLCKSZ, 1, file) != 1)
532 if (fclose(file) != 0)
553 printf(
"rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
581 uint64 n, uint64 total_count,
582 uint64 rec_len, uint64 total_rec_len,
583 uint64 fpi_len, uint64 total_fpi_len,
584 uint64 tot_len, uint64 total_len)
592 if (total_count != 0)
593 n_pct = 100 * (double) n / total_count;
596 if (total_rec_len != 0)
597 rec_len_pct = 100 * (double) rec_len / total_rec_len;
600 if (total_fpi_len != 0)
601 fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
605 tot_len_pct = 100 * (double) tot_len / total_len;
608 "%20" INT64_MODIFIER
"u (%6.02f) "
609 "%20" INT64_MODIFIER
"u (%6.02f) "
610 "%20" INT64_MODIFIER
"u (%6.02f) "
611 "%20" INT64_MODIFIER
"u (%6.02f)\n",
612 name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
613 tot_len, tot_len_pct);
625 uint64 total_count = 0;
626 uint64 total_rec_len = 0;
627 uint64 total_fpi_len = 0;
628 uint64 total_len = 0;
652 total_len = total_rec_len + total_fpi_len;
654 printf(
"WAL statistics between %X/%X and %X/%X:\n",
662 printf(
"%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
663 "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
664 "Type",
"N",
"(%)",
"Record size",
"(%)",
"FPI size",
"(%)",
"Combined size",
"(%)",
665 "----",
"-",
"---",
"-----------",
"---",
"--------",
"---",
"-------------",
"---");
685 tot_len = rec_len + fpi_len;
691 count, total_count, rec_len, total_rec_len,
692 fpi_len, total_fpi_len, tot_len, total_len);
703 tot_len = rec_len + fpi_len;
712 id =
psprintf(
"UNKNOWN (%x)", rj << 4);
715 count, total_count, rec_len, total_rec_len,
716 fpi_len, total_fpi_len, tot_len, total_len);
721 printf(
"%-27s %20s %8s %20s %8s %20s %8s %20s\n",
722 "",
"--------",
"",
"--------",
"",
"--------",
"",
"--------");
733 rec_len_pct = 100 * (double) total_rec_len / total_len;
737 fpi_len_pct = 100 * (double) total_fpi_len / total_len;
740 "%20" INT64_MODIFIER
"u %-9s"
741 "%20" INT64_MODIFIER
"u %-9s"
742 "%20" INT64_MODIFIER
"u %-9s"
743 "%20" INT64_MODIFIER
"u %-6s\n",
744 "Total", stats->
count,
"",
745 total_rec_len,
psprintf(
"[%.02f%%]", rec_len_pct),
746 total_fpi_len,
psprintf(
"[%.02f%%]", fpi_len_pct),
747 total_len,
"[100%]");
753 printf(
_(
"%s decodes and displays PostgreSQL write-ahead logs for debugging.\n\n"),
758 printf(
_(
" -b, --bkp-details output detailed information about backup blocks\n"));
759 printf(
_(
" -B, --block=N with --relation, only show records that modify block N\n"));
760 printf(
_(
" -e, --end=RECPTR stop reading at WAL location RECPTR\n"));
761 printf(
_(
" -f, --follow keep retrying after reaching end of WAL\n"));
762 printf(
_(
" -F, --fork=FORK only show records that modify blocks in fork FORK;\n"
763 " valid names are main, fsm, vm, init\n"));
764 printf(
_(
" -n, --limit=N number of records to display\n"));
765 printf(
_(
" -p, --path=PATH directory in which to find WAL segment files or a\n"
766 " directory with a ./pg_wal that contains such files\n"
767 " (default: current directory, ./pg_wal, $PGDATA/pg_wal)\n"));
768 printf(
_(
" -q, --quiet do not print any output, except for errors\n"));
769 printf(
_(
" -r, --rmgr=RMGR only show records generated by resource manager RMGR;\n"
770 " use --rmgr=list to list valid resource manager names\n"));
771 printf(
_(
" -R, --relation=T/D/R only show records that modify blocks in relation T/D/R\n"));
772 printf(
_(
" -s, --start=RECPTR start reading at WAL location RECPTR\n"));
773 printf(
_(
" -t, --timeline=TLI timeline from which to read WAL records\n"
774 " (default: 1 or the value used in STARTSEG)\n"));
775 printf(
_(
" -V, --version output version information, then exit\n"));
776 printf(
_(
" -w, --fullpage only show records with a full page write\n"));
777 printf(
_(
" --save-fullpage=PATH\n"
778 " save full page images\n"));
779 printf(
_(
" -x, --xid=XID only show records with transaction ID XID\n"));
780 printf(
_(
" -z, --stats[=record] show statistics instead of records\n"
781 " (optionally, show per-record statistics)\n"));
782 printf(
_(
" -?, --help show this help, then exit\n"));
783 printf(
_(
"\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
784 printf(
_(
"%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
801 static struct option long_options[] = {
836 if (strcmp(argv[1],
"--help") == 0 || strcmp(argv[1],
"-?") == 0)
841 if (strcmp(argv[1],
"--version") == 0 || strcmp(argv[1],
"-V") == 0)
843 puts(
"pg_waldump (PostgreSQL) " PG_VERSION);
852 private.timeline = 1;
855 private.endptr_reached =
false;
857 config.
quiet =
false;
872 config.
stats =
false;
885 long_options, &optindex)) != -1)
903 if (sscanf(
optarg,
"%X/%X", &xlogid, &xrecoff) != 2)
909 private.endptr = (uint64) xlogid << 32 | xrecoff;
953 if (sscanf(
optarg,
"custom%03d", &rmid) == 1)
957 pg_log_error(
"custom resource manager \"%s\" does not exist",
986 if (sscanf(
optarg,
"%u/%u/%u",
1001 if (sscanf(
optarg,
"%X/%X", &xlogid, &xrecoff) != 2)
1008 private.startptr = (uint64) xlogid << 32 | xrecoff;
1024 while (*endptr !=
'\0' && isspace((
unsigned char) *endptr))
1027 if (*endptr !=
'\0')
1030 optarg,
"-t/--timeline");
1034 if (errno == ERANGE || val < 1 || val > UINT_MAX)
1037 "-t/--timeline", 1, UINT_MAX);
1041 private.timeline =
val;
1051 pg_log_error(
"invalid transaction ID specification: \"%s\"",
1058 config.
stats =
true;
1062 if (strcmp(
optarg,
"record") == 0)
1064 else if (strcmp(
optarg,
"rmgr") != 0)
1083 pg_log_error(
"option %s requires option %s to be specified",
1084 "-B/--block",
"-R/--relation");
1090 pg_log_error(
"too many command-line arguments (first is \"%s\")",
1100 pg_log_error(
"could not open directory \"%s\": %m", waldir);
1118 if (waldir == NULL &&
directory != NULL)
1123 pg_fatal(
"could not open directory \"%s\": %m", waldir);
1129 pg_fatal(
"could not open file \"%s\"", fname);
1139 pg_log_error(
"start WAL location %X/%X is not inside file \"%s\"",
1159 pg_fatal(
"could not open file \"%s\"", fname);
1165 if (endsegno < segno)
1166 pg_fatal(
"ENDSEG %s is before STARTSEG %s",
1179 private.endptr != (segno + 1) *
WalSegSz)
1181 pg_log_error(
"end WAL location %X/%X is not inside file \"%s\"",
1206 if (!xlogreader_state)
1207 pg_fatal(
"out of memory while allocating a WAL reading processor");
1213 pg_fatal(
"could not find a valid record after %X/%X",
1221 if (first_record !=
private.startptr &&
1223 printf(
ngettext(
"first record is after %X/%X, at %X/%X, skipping over %u byte\n",
1224 "first record is after %X/%X, at %X/%X, skipping over %u bytes\n",
1225 (first_record -
private.startptr)),
1228 (
uint32) (first_record -
private.startptr));
1231 stats.startptr = first_record;
1245 if (!config.
follow ||
private.endptr_reached)
1281 if (config.
stats ==
true)
1284 stats.endptr = xlogreader_state->
EndRecPtr;
1308 pg_fatal(
"error in WAL record at %X/%X: %s",
#define InvalidBlockNumber
static bool BlockNumberIsValid(BlockNumber 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
if(TABLE==NULL||TABLE_index==NULL)
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)
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 void create_fullpage_directory(char *path)
static bool verify_directory(const char *directory)
static const RelFileLocator emptyRelFileLocator
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 void XLogRecordSaveFPWs(XLogReaderState *record, const char *savepath)
static char * identify_target_directory(char *directory, char *fname)
static bool XLogRecordHasFPW(XLogReaderState *record)
static void sigint_handler(SIGNAL_ARGS)
static bool XLogRecordMatchesRelationBlock(XLogReaderState *record, RelFileLocator matchRlocator, BlockNumber matchBlock, ForkNumber matchFork)
int pg_mkdir_p(char *path, int omode)
int pg_strcasecmp(const char *s1, const char *s2)
int pg_check_dir(const char *dir)
const char * get_progname(const char *argv0)
pqsigfunc pqsignal(int signo, pqsigfunc func)
static int fd(const char *x, int i)
char * psprintf(const char *fmt,...)
#define RelFileLocatorEquals(locator1, locator2)
ForkNumber forkname_to_number(const char *forkName)
const char *const forkNames[]
#define RelFileNumberIsValid(relnumber)
#define RM_MAX_BUILTIN_ID
static bool RmgrIdIsCustom(int rmid)
#define RmgrIdIsValid(rmid)
const RmgrDescData * GetRmgrDesc(RmgrId rmid)
void pg_usleep(long microsec)
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
RelFileLocator filter_by_relation
char * save_fullpage_path
bool filter_by_rmgr[RM_MAX_ID+1]
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)
static bool IsXLogFileName(const char *fname)
static void XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes)
#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest)
static void XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
#define XLByteInSeg(xlrp, 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)
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)
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 RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
#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