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)
257 "invalid WAL segment size in WAL file \"%s\" (%d bytes)",
265 pg_fatal(
"could not read file \"%s\": %m",
268 pg_fatal(
"could not read file \"%s\": read %d of %d",
269 fname, r, XLOG_BLCKSZ);
329 pg_fatal(
"could not locate WAL file \"%s\"", fname);
331 pg_fatal(
"could not find any WAL file");
353 for (tries = 0; tries < 10; tries++)
356 if (
state->seg.ws_file >= 0)
360 int save_errno = errno;
372 pg_fatal(
"could not find file \"%s\": %m", fname);
384 state->seg.ws_file = -1;
393 int count = XLOG_BLCKSZ;
398 if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
400 else if (targetPagePtr + reqLen <= private->endptr)
401 count =
private->endptr - targetPagePtr;
404 private->endptr_reached =
true;
409 if (!
WALRead(
state, readBuff, targetPagePtr, count, private->timeline,
416 state->segcxt.ws_segsize);
421 pg_fatal(
"could not read from file \"%s\", offset %d: %m",
425 pg_fatal(
"could not read from file \"%s\", offset %d: read %d of %d",
452 &rlocator, &forknum, &blk, NULL))
518 &rnode, &fork, &blk, NULL);
523 pg_fatal(
"invalid fork number: %u", fork);
534 if (fwrite(page, BLCKSZ, 1, file) != 1)
537 if (fclose(file) != 0)
558 printf(
"rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
586 uint64 n, uint64 total_count,
587 uint64 rec_len, uint64 total_rec_len,
588 uint64 fpi_len, uint64 total_fpi_len,
589 uint64 tot_len, uint64 total_len)
597 if (total_count != 0)
598 n_pct = 100 * (double) n / total_count;
601 if (total_rec_len != 0)
602 rec_len_pct = 100 * (double) rec_len / total_rec_len;
605 if (total_fpi_len != 0)
606 fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
610 tot_len_pct = 100 * (double) tot_len / total_len;
613 "%20" INT64_MODIFIER
"u (%6.02f) "
614 "%20" INT64_MODIFIER
"u (%6.02f) "
615 "%20" INT64_MODIFIER
"u (%6.02f) "
616 "%20" INT64_MODIFIER
"u (%6.02f)\n",
617 name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
618 tot_len, tot_len_pct);
630 uint64 total_count = 0;
631 uint64 total_rec_len = 0;
632 uint64 total_fpi_len = 0;
633 uint64 total_len = 0;
657 total_len = total_rec_len + total_fpi_len;
659 printf(
"WAL statistics between %X/%X and %X/%X:\n",
667 printf(
"%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
668 "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
669 "Type",
"N",
"(%)",
"Record size",
"(%)",
"FPI size",
"(%)",
"Combined size",
"(%)",
670 "----",
"-",
"---",
"-----------",
"---",
"--------",
"---",
"-------------",
"---");
690 tot_len = rec_len + fpi_len;
696 count, total_count, rec_len, total_rec_len,
697 fpi_len, total_fpi_len, tot_len, total_len);
708 tot_len = rec_len + fpi_len;
717 id =
psprintf(
"UNKNOWN (%x)", rj << 4);
720 count, total_count, rec_len, total_rec_len,
721 fpi_len, total_fpi_len, tot_len, total_len);
726 printf(
"%-27s %20s %8s %20s %8s %20s %8s %20s\n",
727 "",
"--------",
"",
"--------",
"",
"--------",
"",
"--------");
738 rec_len_pct = 100 * (double) total_rec_len / total_len;
742 fpi_len_pct = 100 * (double) total_fpi_len / total_len;
745 "%20" INT64_MODIFIER
"u %-9s"
746 "%20" INT64_MODIFIER
"u %-9s"
747 "%20" INT64_MODIFIER
"u %-9s"
748 "%20" INT64_MODIFIER
"u %-6s\n",
749 "Total", stats->
count,
"",
750 total_rec_len,
psprintf(
"[%.02f%%]", rec_len_pct),
751 total_fpi_len,
psprintf(
"[%.02f%%]", fpi_len_pct),
752 total_len,
"[100%]");
758 printf(
_(
"%s decodes and displays PostgreSQL write-ahead logs for debugging.\n\n"),
763 printf(
_(
" -b, --bkp-details output detailed information about backup blocks\n"));
764 printf(
_(
" -B, --block=N with --relation, only show records that modify block N\n"));
765 printf(
_(
" -e, --end=RECPTR stop reading at WAL location RECPTR\n"));
766 printf(
_(
" -f, --follow keep retrying after reaching end of WAL\n"));
767 printf(
_(
" -F, --fork=FORK only show records that modify blocks in fork FORK;\n"
768 " valid names are main, fsm, vm, init\n"));
769 printf(
_(
" -n, --limit=N number of records to display\n"));
770 printf(
_(
" -p, --path=PATH directory in which to find WAL segment files or a\n"
771 " directory with a ./pg_wal that contains such files\n"
772 " (default: current directory, ./pg_wal, $PGDATA/pg_wal)\n"));
773 printf(
_(
" -q, --quiet do not print any output, except for errors\n"));
774 printf(
_(
" -r, --rmgr=RMGR only show records generated by resource manager RMGR;\n"
775 " use --rmgr=list to list valid resource manager names\n"));
776 printf(
_(
" -R, --relation=T/D/R only show records that modify blocks in relation T/D/R\n"));
777 printf(
_(
" -s, --start=RECPTR start reading at WAL location RECPTR\n"));
778 printf(
_(
" -t, --timeline=TLI timeline from which to read WAL records\n"
779 " (default: 1 or the value used in STARTSEG)\n"));
780 printf(
_(
" -V, --version output version information, then exit\n"));
781 printf(
_(
" -w, --fullpage only show records with a full page write\n"));
782 printf(
_(
" -x, --xid=XID only show records with transaction ID XID\n"));
783 printf(
_(
" -z, --stats[=record] show statistics instead of records\n"
784 " (optionally, show per-record statistics)\n"));
785 printf(
_(
" --save-fullpage=DIR save full page images to DIR\n"));
786 printf(
_(
" -?, --help show this help, then exit\n"));
787 printf(
_(
"\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
788 printf(
_(
"%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
805 static struct option long_options[] = {
840 if (strcmp(argv[1],
"--help") == 0 || strcmp(argv[1],
"-?") == 0)
845 if (strcmp(argv[1],
"--version") == 0 || strcmp(argv[1],
"-V") == 0)
847 puts(
"pg_waldump (PostgreSQL) " PG_VERSION);
856 private.timeline = 1;
859 private.endptr_reached =
false;
861 config.
quiet =
false;
876 config.
stats =
false;
889 long_options, &optindex)) != -1)
907 if (sscanf(
optarg,
"%X/%X", &xlogid, &xrecoff) != 2)
913 private.endptr = (uint64) xlogid << 32 | xrecoff;
957 if (sscanf(
optarg,
"custom%03d", &rmid) == 1)
961 pg_log_error(
"custom resource manager \"%s\" does not exist",
990 if (sscanf(
optarg,
"%u/%u/%u",
1005 if (sscanf(
optarg,
"%X/%X", &xlogid, &xrecoff) != 2)
1012 private.startptr = (uint64) xlogid << 32 | xrecoff;
1028 while (*endptr !=
'\0' && isspace((
unsigned char) *endptr))
1031 if (*endptr !=
'\0')
1034 optarg,
"-t/--timeline");
1038 if (errno == ERANGE || val < 1 || val > UINT_MAX)
1041 "-t/--timeline", 1, UINT_MAX);
1045 private.timeline =
val;
1055 pg_log_error(
"invalid transaction ID specification: \"%s\"",
1062 config.
stats =
true;
1066 if (strcmp(
optarg,
"record") == 0)
1068 else if (strcmp(
optarg,
"rmgr") != 0)
1087 pg_log_error(
"option %s requires option %s to be specified",
1088 "-B/--block",
"-R/--relation");
1094 pg_log_error(
"too many command-line arguments (first is \"%s\")",
1104 pg_log_error(
"could not open directory \"%s\": %m", waldir);
1122 if (waldir == NULL &&
directory != NULL)
1127 pg_fatal(
"could not open directory \"%s\": %m", waldir);
1133 pg_fatal(
"could not open file \"%s\"", fname);
1143 pg_log_error(
"start WAL location %X/%X is not inside file \"%s\"",
1163 pg_fatal(
"could not open file \"%s\"", fname);
1169 if (endsegno < segno)
1170 pg_fatal(
"ENDSEG %s is before STARTSEG %s",
1183 private.endptr != (segno + 1) *
WalSegSz)
1185 pg_log_error(
"end WAL location %X/%X is not inside file \"%s\"",
1210 if (!xlogreader_state)
1211 pg_fatal(
"out of memory while allocating a WAL reading processor");
1217 pg_fatal(
"could not find a valid record after %X/%X",
1225 if (first_record !=
private.startptr &&
1228 "first record is after %X/%X, at %X/%X, skipping over %u bytes",
1229 (first_record -
private.startptr)),
1232 (
uint32) (first_record -
private.startptr));
1235 stats.startptr = first_record;
1249 if (!config.
follow ||
private.endptr_reached)
1285 if (config.
stats ==
true)
1288 stats.endptr = xlogreader_state->
EndRecPtr;
1312 pg_fatal(
"error in WAL record at %X/%X: %s",
#define InvalidBlockNumber
static bool BlockNumberIsValid(BlockNumber blockNumber)
#define ngettext(s, p, n)
#define Assert(condition)
#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)
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