diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2015-03-10 22:33:24 -0400 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2015-04-21 19:03:49 -0400 |
commit | b0a738f428ca4e52695c0f019c1560c64cc59aef (patch) | |
tree | 2d1a4aae451c78ff08fc59a7913a7e7410fbbad6 /contrib/pg_xlogdump | |
parent | 0275ecf31cda9329ee822a6a806a2018144520ed (diff) | |
download | postgresql-b0a738f428ca4e52695c0f019c1560c64cc59aef.tar.gz postgresql-b0a738f428ca4e52695c0f019c1560c64cc59aef.zip |
Move pg_xlogdump from contrib/ to src/bin/
Reviewed-by: Michael Paquier <michael.paquier@gmail.com>
Diffstat (limited to 'contrib/pg_xlogdump')
-rw-r--r-- | contrib/pg_xlogdump/.gitignore | 21 | ||||
-rw-r--r-- | contrib/pg_xlogdump/Makefile | 31 | ||||
-rw-r--r-- | contrib/pg_xlogdump/compat.c | 99 | ||||
-rw-r--r-- | contrib/pg_xlogdump/pg_xlogdump.c | 1007 | ||||
-rw-r--r-- | contrib/pg_xlogdump/rmgrdesc.c | 37 | ||||
-rw-r--r-- | contrib/pg_xlogdump/rmgrdesc.h | 22 |
6 files changed, 0 insertions, 1217 deletions
diff --git a/contrib/pg_xlogdump/.gitignore b/contrib/pg_xlogdump/.gitignore deleted file mode 100644 index 16cf749ee48..00000000000 --- a/contrib/pg_xlogdump/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -/pg_xlogdump -# Source files copied from src/backend/access/ -/brindesc.c -/clogdesc.c -/committsdesc.c -/dbasedesc.c -/gindesc.c -/gistdesc.c -/hashdesc.c -/heapdesc.c -/mxactdesc.c -/nbtdesc.c -/relmapdesc.c -/seqdesc.c -/smgrdesc.c -/spgdesc.c -/standbydesc.c -/tblspcdesc.c -/xactdesc.c -/xlogdesc.c -/xlogreader.c diff --git a/contrib/pg_xlogdump/Makefile b/contrib/pg_xlogdump/Makefile deleted file mode 100644 index 30a8706948c..00000000000 --- a/contrib/pg_xlogdump/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# contrib/pg_xlogdump/Makefile - -PGFILEDESC = "pg_xlogdump - decode and display WAL" -PGAPPICON=win32 - -PROGRAM = pg_xlogdump -OBJS = pg_xlogdump.o compat.o xlogreader.o rmgrdesc.o \ - $(RMGRDESCOBJS) $(WIN32RES) - -RMGRDESCSOURCES = $(notdir $(wildcard $(top_srcdir)/src/backend/access/rmgrdesc/*desc.c)) -RMGRDESCOBJS = $(patsubst %.c,%.o,$(RMGRDESCSOURCES)) - -EXTRA_CLEAN = $(RMGRDESCSOURCES) xlogreader.c - -ifdef USE_PGXS -$(error "pg_xlogdump cannot be built with PGXS") -endif - -subdir = contrib/pg_xlogdump -top_builddir = ../.. -include $(top_builddir)/src/Makefile.global -include $(top_srcdir)/contrib/contrib-global.mk - - -override CPPFLAGS := -DFRONTEND $(CPPFLAGS) - -xlogreader.c: % : $(top_srcdir)/src/backend/access/transam/% - rm -f $@ && $(LN_S) $< . - -$(RMGRDESCSOURCES): % : $(top_srcdir)/src/backend/access/rmgrdesc/% - rm -f $@ && $(LN_S) $< . diff --git a/contrib/pg_xlogdump/compat.c b/contrib/pg_xlogdump/compat.c deleted file mode 100644 index 4f5cad67060..00000000000 --- a/contrib/pg_xlogdump/compat.c +++ /dev/null @@ -1,99 +0,0 @@ -/*------------------------------------------------------------------------- - * - * compat.c - * Reimplementations of various backend functions. - * - * Portions Copyright (c) 2013-2015, PostgreSQL Global Development Group - * - * IDENTIFICATION - * contrib/pg_xlogdump/compat.c - * - * This file contains client-side implementations for various backend - * functions that the rm_desc functions in *desc.c files rely on. - * - *------------------------------------------------------------------------- - */ - -/* ugly hack, same as in e.g pg_controldata */ -#define FRONTEND 1 -#include "postgres.h" - -#include <time.h> - -#include "utils/datetime.h" -#include "lib/stringinfo.h" - -/* copied from timestamp.c */ -pg_time_t -timestamptz_to_time_t(TimestampTz t) -{ - pg_time_t result; - -#ifdef HAVE_INT64_TIMESTAMP - result = (pg_time_t) (t / USECS_PER_SEC + - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY)); -#else - result = (pg_time_t) (t + - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY)); -#endif - return result; -} - -/* - * Stopgap implementation of timestamptz_to_str that doesn't depend on backend - * infrastructure. This will work for timestamps that are within the range - * of the platform time_t type. (pg_time_t is compatible except for possibly - * being wider.) - * - * XXX the return value points to a static buffer, so beware of using more - * than one result value concurrently. - * - * XXX: The backend timestamp infrastructure should instead be split out and - * moved into src/common. That's a large project though. - */ -const char * -timestamptz_to_str(TimestampTz dt) -{ - static char buf[MAXDATELEN + 1]; - char ts[MAXDATELEN + 1]; - char zone[MAXDATELEN + 1]; - time_t result = (time_t) timestamptz_to_time_t(dt); - struct tm *ltime = localtime(&result); - - strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", ltime); - strftime(zone, sizeof(zone), "%Z", ltime); - -#ifdef HAVE_INT64_TIMESTAMP - sprintf(buf, "%s.%06d %s", ts, (int) (dt % USECS_PER_SEC), zone); -#else - sprintf(buf, "%s.%.6f %s", ts, fabs(dt - floor(dt)), zone); -#endif - - return buf; -} - -/* - * Provide a hacked up compat layer for StringInfos so xlog desc functions can - * be linked/called. - */ -void -appendStringInfo(StringInfo str, const char *fmt,...) -{ - va_list args; - - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); -} - -void -appendStringInfoString(StringInfo str, const char *string) -{ - appendStringInfo(str, "%s", string); -} - -void -appendStringInfoChar(StringInfo str, char ch) -{ - appendStringInfo(str, "%c", ch); -} diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c deleted file mode 100644 index 4f297e95720..00000000000 --- a/contrib/pg_xlogdump/pg_xlogdump.c +++ /dev/null @@ -1,1007 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pg_xlogdump.c - decode and display WAL - * - * Copyright (c) 2013-2015, PostgreSQL Global Development Group - * - * IDENTIFICATION - * contrib/pg_xlogdump/pg_xlogdump.c - *------------------------------------------------------------------------- - */ - -#define FRONTEND 1 -#include "postgres.h" - -#include <dirent.h> -#include <unistd.h> - -#include "access/xlogreader.h" -#include "access/xlogrecord.h" -#include "access/xlog_internal.h" -#include "access/transam.h" -#include "common/fe_memutils.h" -#include "getopt_long.h" -#include "rmgrdesc.h" - - -static const char *progname; - -typedef struct XLogDumpPrivate -{ - TimeLineID timeline; - char *inpath; - XLogRecPtr startptr; - XLogRecPtr endptr; - bool endptr_reached; -} XLogDumpPrivate; - -typedef struct XLogDumpConfig -{ - /* display options */ - bool bkp_details; - int stop_after_records; - int already_displayed_records; - bool follow; - bool stats; - bool stats_per_record; - - /* filter options */ - int filter_by_rmgr; - TransactionId filter_by_xid; - bool filter_by_xid_enabled; -} XLogDumpConfig; - -typedef struct Stats -{ - uint64 count; - uint64 rec_len; - uint64 fpi_len; -} Stats; - -#define MAX_XLINFO_TYPES 16 - -typedef struct XLogDumpStats -{ - uint64 count; - Stats rmgr_stats[RM_NEXT_ID]; - Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES]; -} XLogDumpStats; - -static void fatal_error(const char *fmt,...) pg_attribute_printf(1, 2); - -/* - * Big red button to push when things go horribly wrong. - */ -static void -fatal_error(const char *fmt,...) -{ - va_list args; - - fflush(stdout); - - fprintf(stderr, "%s: FATAL: ", progname); - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fputc('\n', stderr); - - exit(EXIT_FAILURE); -} - -static void -print_rmgr_list(void) -{ - int i; - - for (i = 0; i <= RM_MAX_ID; i++) - { - printf("%s\n", RmgrDescTable[i].rm_name); - } -} - -/* - * Check whether directory exists and whether we can open it. Keep errno set so - * that the caller can report errors somewhat more accurately. - */ -static bool -verify_directory(const char *directory) -{ - DIR *dir = opendir(directory); - - if (dir == NULL) - return false; - closedir(dir); - return true; -} - -/* - * Split a pathname as dirname(1) and basename(1) would. - * - * XXX this probably doesn't do very well on Windows. We probably need to - * apply canonicalize_path(), at the very least. - */ -static void -split_path(const char *path, char **dir, char **fname) -{ - char *sep; - - /* split filepath into directory & filename */ - sep = strrchr(path, '/'); - - /* directory path */ - if (sep != NULL) - { - *dir = pg_strdup(path); - (*dir)[(sep - path) + 1] = '\0'; /* no strndup */ - *fname = pg_strdup(sep + 1); - } - /* local directory */ - else - { - *dir = NULL; - *fname = pg_strdup(path); - } -} - -/* - * Try to find the file in several places: - * if directory == NULL: - * fname - * XLOGDIR / fname - * $PGDATA / XLOGDIR / fname - * else - * directory / fname - * directory / XLOGDIR / fname - * - * return a read only fd - */ -static int -fuzzy_open_file(const char *directory, const char *fname) -{ - int fd = -1; - char fpath[MAXPGPATH]; - - if (directory == NULL) - { - const char *datadir; - - /* fname */ - fd = open(fname, O_RDONLY | PG_BINARY, 0); - if (fd < 0 && errno != ENOENT) - return -1; - else if (fd >= 0) - return fd; - - /* XLOGDIR / fname */ - snprintf(fpath, MAXPGPATH, "%s/%s", - XLOGDIR, fname); - fd = open(fpath, O_RDONLY | PG_BINARY, 0); - if (fd < 0 && errno != ENOENT) - return -1; - else if (fd >= 0) - return fd; - - datadir = getenv("PGDATA"); - /* $PGDATA / XLOGDIR / fname */ - if (datadir != NULL) - { - snprintf(fpath, MAXPGPATH, "%s/%s/%s", - datadir, XLOGDIR, fname); - fd = open(fpath, O_RDONLY | PG_BINARY, 0); - if (fd < 0 && errno != ENOENT) - return -1; - else if (fd >= 0) - return fd; - } - } - else - { - /* directory / fname */ - snprintf(fpath, MAXPGPATH, "%s/%s", - directory, fname); - fd = open(fpath, O_RDONLY | PG_BINARY, 0); - if (fd < 0 && errno != ENOENT) - return -1; - else if (fd >= 0) - return fd; - - /* directory / XLOGDIR / fname */ - snprintf(fpath, MAXPGPATH, "%s/%s/%s", - directory, XLOGDIR, fname); - fd = open(fpath, O_RDONLY | PG_BINARY, 0); - if (fd < 0 && errno != ENOENT) - return -1; - else if (fd >= 0) - return fd; - } - return -1; -} - -/* - * Read count bytes from a segment file in the specified directory, for the - * given timeline, containing the specified record pointer; store the data in - * the passed buffer. - */ -static void -XLogDumpXLogRead(const char *directory, TimeLineID timeline_id, - XLogRecPtr startptr, char *buf, Size count) -{ - char *p; - XLogRecPtr recptr; - Size nbytes; - - static int sendFile = -1; - static XLogSegNo sendSegNo = 0; - static uint32 sendOff = 0; - - p = buf; - recptr = startptr; - nbytes = count; - - while (nbytes > 0) - { - uint32 startoff; - int segbytes; - int readbytes; - - startoff = recptr % XLogSegSize; - - if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo)) - { - char fname[MAXFNAMELEN]; - - /* Switch to another logfile segment */ - if (sendFile >= 0) - close(sendFile); - - XLByteToSeg(recptr, sendSegNo); - - XLogFileName(fname, timeline_id, sendSegNo); - - sendFile = fuzzy_open_file(directory, fname); - - if (sendFile < 0) - fatal_error("could not find file \"%s\": %s", - fname, strerror(errno)); - sendOff = 0; - } - - /* Need to seek in the file? */ - if (sendOff != startoff) - { - if (lseek(sendFile, (off_t) startoff, SEEK_SET) < 0) - { - int err = errno; - char fname[MAXPGPATH]; - - XLogFileName(fname, timeline_id, sendSegNo); - - fatal_error("could not seek in log segment %s to offset %u: %s", - fname, startoff, strerror(err)); - } - sendOff = startoff; - } - - /* How many bytes are within this segment? */ - if (nbytes > (XLogSegSize - startoff)) - segbytes = XLogSegSize - startoff; - else - segbytes = nbytes; - - readbytes = read(sendFile, p, segbytes); - if (readbytes <= 0) - { - int err = errno; - char fname[MAXPGPATH]; - - XLogFileName(fname, timeline_id, sendSegNo); - - fatal_error("could not read from log segment %s, offset %d, length %d: %s", - fname, sendOff, segbytes, strerror(err)); - } - - /* Update state for read */ - recptr += readbytes; - - sendOff += readbytes; - nbytes -= readbytes; - p += readbytes; - } -} - -/* - * XLogReader read_page callback - */ -static int -XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, - XLogRecPtr targetPtr, char *readBuff, TimeLineID *curFileTLI) -{ - XLogDumpPrivate *private = state->private_data; - int count = XLOG_BLCKSZ; - - if (private->endptr != InvalidXLogRecPtr) - { - if (targetPagePtr + XLOG_BLCKSZ <= private->endptr) - count = XLOG_BLCKSZ; - else if (targetPagePtr + reqLen <= private->endptr) - count = private->endptr - targetPagePtr; - else - { - private->endptr_reached = true; - return -1; - } - } - - XLogDumpXLogRead(private->inpath, private->timeline, targetPagePtr, - readBuff, count); - - return count; -} - -/* - * Store per-rmgr and per-record statistics for a given record. - */ -static void -XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, - XLogReaderState *record) -{ - RmgrId rmid; - uint8 recid; - uint32 rec_len; - uint32 fpi_len; - int block_id; - - stats->count++; - - rmid = XLogRecGetRmid(record); - rec_len = XLogRecGetDataLen(record) + SizeOfXLogRecord; - - /* - * Calculate the amount of FPI data in the record. - * - * XXX: We peek into xlogreader's private decoded backup blocks for the - * bimg_len indicating the length of FPI data. It doesn't seem worth it to - * add an accessor macro for this. - */ - fpi_len = 0; - for (block_id = 0; block_id <= record->max_block_id; block_id++) - { - if (XLogRecHasBlockImage(record, block_id)) - fpi_len += record->blocks[block_id].bimg_len; - } - - /* Update per-rmgr statistics */ - - stats->rmgr_stats[rmid].count++; - stats->rmgr_stats[rmid].rec_len += rec_len; - stats->rmgr_stats[rmid].fpi_len += fpi_len; - - /* - * Update per-record statistics, where the record is identified by a - * combination of the RmgrId and the four bits of the xl_info field that - * are the rmgr's domain (resulting in sixteen possible entries per - * RmgrId). - */ - - recid = XLogRecGetInfo(record) >> 4; - - stats->record_stats[rmid][recid].count++; - stats->record_stats[rmid][recid].rec_len += rec_len; - stats->record_stats[rmid][recid].fpi_len += fpi_len; -} - -/* - * Print a record to stdout - */ -static void -XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record) -{ - const char *id; - const RmgrDescData *desc = &RmgrDescTable[XLogRecGetRmid(record)]; - RelFileNode rnode; - ForkNumber forknum; - BlockNumber blk; - int block_id; - uint8 info = XLogRecGetInfo(record); - XLogRecPtr xl_prev = XLogRecGetPrev(record); - - id = desc->rm_identify(info); - if (id == NULL) - id = psprintf("UNKNOWN (%x)", info & ~XLR_INFO_MASK); - - printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ", - desc->rm_name, - XLogRecGetDataLen(record), XLogRecGetTotalLen(record), - XLogRecGetXid(record), - (uint32) (record->ReadRecPtr >> 32), (uint32) record->ReadRecPtr, - (uint32) (xl_prev >> 32), (uint32) xl_prev); - printf("desc: %s ", id); - - /* the desc routine will printf the description directly to stdout */ - desc->rm_desc(NULL, record); - - if (!config->bkp_details) - { - /* print block references (short format) */ - for (block_id = 0; block_id <= record->max_block_id; block_id++) - { - if (!XLogRecHasBlockRef(record, block_id)) - continue; - - XLogRecGetBlockTag(record, block_id, &rnode, &forknum, &blk); - if (forknum != MAIN_FORKNUM) - printf(", blkref #%u: rel %u/%u/%u fork %s blk %u", - block_id, - rnode.spcNode, rnode.dbNode, rnode.relNode, - forkNames[forknum], - blk); - else - printf(", blkref #%u: rel %u/%u/%u blk %u", - block_id, - rnode.spcNode, rnode.dbNode, rnode.relNode, - blk); - if (XLogRecHasBlockImage(record, block_id)) - printf(" FPW"); - } - putchar('\n'); - } - else - { - /* print block references (detailed format) */ - putchar('\n'); - for (block_id = 0; block_id <= record->max_block_id; block_id++) - { - if (!XLogRecHasBlockRef(record, block_id)) - continue; - - XLogRecGetBlockTag(record, block_id, &rnode, &forknum, &blk); - printf("\tblkref #%u: rel %u/%u/%u fork %s blk %u", - block_id, - rnode.spcNode, rnode.dbNode, rnode.relNode, - forkNames[forknum], - blk); - if (XLogRecHasBlockImage(record, block_id)) - { - if (record->blocks[block_id].bimg_info & - BKPIMAGE_IS_COMPRESSED) - { - printf(" (FPW); hole: offset: %u, length: %u, compression saved: %u\n", - record->blocks[block_id].hole_offset, - record->blocks[block_id].hole_length, - BLCKSZ - - record->blocks[block_id].hole_length - - record->blocks[block_id].bimg_len); - } - else - { - printf(" (FPW); hole: offset: %u, length: %u\n", - record->blocks[block_id].hole_offset, - record->blocks[block_id].hole_length); - } - } - putchar('\n'); - } - } -} - -/* - * Display a single row of record counts and sizes for an rmgr or record. - */ -static void -XLogDumpStatsRow(const char *name, - uint64 n, double n_pct, - uint64 rec_len, double rec_len_pct, - uint64 fpi_len, double fpi_len_pct, - uint64 total_len, double total_len_pct) -{ - printf("%-27s " - "%20" INT64_MODIFIER "u (%6.02f) " - "%20" INT64_MODIFIER "u (%6.02f) " - "%20" INT64_MODIFIER "u (%6.02f) " - "%20" INT64_MODIFIER "u (%6.02f)\n", - name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct, - total_len, total_len_pct); -} - - -/* - * Display summary statistics about the records seen so far. - */ -static void -XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) -{ - int ri, rj; - uint64 total_count = 0; - uint64 total_rec_len = 0; - uint64 total_fpi_len = 0; - uint64 total_len = 0; - - /* --- - * Make a first pass to calculate column totals: - * count(*), - * sum(xl_len+SizeOfXLogRecord), - * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and - * sum(xl_tot_len). - * These are used to calculate percentages for each record type. - * --- - */ - - for (ri = 0; ri < RM_NEXT_ID; ri++) - { - total_count += stats->rmgr_stats[ri].count; - total_rec_len += stats->rmgr_stats[ri].rec_len; - total_fpi_len += stats->rmgr_stats[ri].fpi_len; - } - total_len = total_rec_len+total_fpi_len; - - /* - * 27 is strlen("Transaction/COMMIT_PREPARED"), - * 20 is strlen(2^64), 8 is strlen("(100.00%)") - */ - - printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n" - "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n", - "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)", - "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---"); - - for (ri = 0; ri < RM_NEXT_ID; ri++) - { - uint64 count, rec_len, fpi_len, tot_len; - const RmgrDescData *desc = &RmgrDescTable[ri]; - - if (!config->stats_per_record) - { - count = stats->rmgr_stats[ri].count; - rec_len = stats->rmgr_stats[ri].rec_len; - fpi_len = stats->rmgr_stats[ri].fpi_len; - tot_len = rec_len + fpi_len; - - XLogDumpStatsRow(desc->rm_name, - count, 100 * (double) count / total_count, - rec_len, 100 * (double) rec_len / total_rec_len, - fpi_len, 100 * (double) fpi_len / total_fpi_len, - tot_len, 100 * (double) tot_len / total_len); - } - else - { - for (rj = 0; rj < MAX_XLINFO_TYPES; rj++) - { - const char *id; - - count = stats->record_stats[ri][rj].count; - rec_len = stats->record_stats[ri][rj].rec_len; - fpi_len = stats->record_stats[ri][rj].fpi_len; - tot_len = rec_len + fpi_len; - - /* Skip undefined combinations and ones that didn't occur */ - if (count == 0) - continue; - - /* the upper four bits in xl_info are the rmgr's */ - id = desc->rm_identify(rj << 4); - if (id == NULL) - id = psprintf("UNKNOWN (%x)", rj << 4); - - XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id), - count, 100 * (double) count / total_count, - rec_len, 100 * (double) rec_len / total_rec_len, - fpi_len, 100 * (double) fpi_len / total_fpi_len, - tot_len, 100 * (double) tot_len / total_len); - } - } - } - - printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n", - "", "--------", "", "--------", "", "--------", "", "--------"); - - /* - * The percentages in earlier rows were calculated against the - * column total, but the ones that follow are against the row total. - * Note that these are displayed with a % symbol to differentiate - * them from the earlier ones, and are thus up to 9 characters long. - */ - - printf("%-27s " - "%20" INT64_MODIFIER "u %-9s" - "%20" INT64_MODIFIER "u %-9s" - "%20" INT64_MODIFIER "u %-9s" - "%20" INT64_MODIFIER "u %-6s\n", - "Total", stats->count, "", - total_rec_len, psprintf("[%.02f%%]", 100 * (double)total_rec_len / total_len), - total_fpi_len, psprintf("[%.02f%%]", 100 * (double)total_fpi_len / total_len), - total_len, "[100%]"); -} - -static void -usage(void) -{ - printf("%s decodes and displays PostgreSQL transaction logs for debugging.\n\n", - progname); - printf("Usage:\n"); - printf(" %s [OPTION]... [STARTSEG [ENDSEG]] \n", progname); - printf("\nOptions:\n"); - printf(" -b, --bkp-details output detailed information about backup blocks\n"); - printf(" -e, --end=RECPTR stop reading at log position RECPTR\n"); - printf(" -f, --follow keep retrying after reaching end of WAL\n"); - printf(" -n, --limit=N number of records to display\n"); - printf(" -p, --path=PATH directory in which to find log segment files\n"); - printf(" (default: ./pg_xlog)\n"); - printf(" -r, --rmgr=RMGR only show records generated by resource manager RMGR\n"); - printf(" use --rmgr=list to list valid resource manager names\n"); - printf(" -s, --start=RECPTR start reading at log position RECPTR\n"); - printf(" -t, --timeline=TLI timeline from which to read log records\n"); - printf(" (default: 1 or the value used in STARTSEG)\n"); - printf(" -V, --version output version information, then exit\n"); - printf(" -x, --xid=XID only show records with TransactionId XID\n"); - printf(" -z, --stats[=record] show statistics instead of records\n"); - printf(" (optionally, show per-record statistics)\n"); - printf(" -?, --help show this help, then exit\n"); -} - -int -main(int argc, char **argv) -{ - uint32 xlogid; - uint32 xrecoff; - XLogReaderState *xlogreader_state; - XLogDumpPrivate private; - XLogDumpConfig config; - XLogDumpStats stats; - XLogRecord *record; - XLogRecPtr first_record; - char *errormsg; - - static struct option long_options[] = { - {"bkp-details", no_argument, NULL, 'b'}, - {"end", required_argument, NULL, 'e'}, - {"follow", no_argument, NULL, 'f'}, - {"help", no_argument, NULL, '?'}, - {"limit", required_argument, NULL, 'n'}, - {"path", required_argument, NULL, 'p'}, - {"rmgr", required_argument, NULL, 'r'}, - {"start", required_argument, NULL, 's'}, - {"timeline", required_argument, NULL, 't'}, - {"xid", required_argument, NULL, 'x'}, - {"version", no_argument, NULL, 'V'}, - {"stats", optional_argument, NULL, 'z'}, - {NULL, 0, NULL, 0} - }; - - int option; - int optindex = 0; - - progname = get_progname(argv[0]); - - memset(&private, 0, sizeof(XLogDumpPrivate)); - memset(&config, 0, sizeof(XLogDumpConfig)); - memset(&stats, 0, sizeof(XLogDumpStats)); - - private.timeline = 1; - private.startptr = InvalidXLogRecPtr; - private.endptr = InvalidXLogRecPtr; - private.endptr_reached = false; - - config.bkp_details = false; - config.stop_after_records = -1; - config.already_displayed_records = 0; - config.follow = false; - config.filter_by_rmgr = -1; - config.filter_by_xid = InvalidTransactionId; - config.filter_by_xid_enabled = false; - config.stats = false; - config.stats_per_record = false; - - if (argc <= 1) - { - fprintf(stderr, "%s: no arguments specified\n", progname); - goto bad_argument; - } - - while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:z", - long_options, &optindex)) != -1) - { - switch (option) - { - case 'b': - config.bkp_details = true; - break; - case 'e': - if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2) - { - fprintf(stderr, "%s: could not parse end log position \"%s\"\n", - progname, optarg); - goto bad_argument; - } - private.endptr = (uint64) xlogid << 32 | xrecoff; - break; - case 'f': - config.follow = true; - break; - case '?': - usage(); - exit(EXIT_SUCCESS); - break; - case 'n': - if (sscanf(optarg, "%d", &config.stop_after_records) != 1) - { - fprintf(stderr, "%s: could not parse limit \"%s\"\n", - progname, optarg); - goto bad_argument; - } - break; - case 'p': - private.inpath = pg_strdup(optarg); - break; - case 'r': - { - int i; - - if (pg_strcasecmp(optarg, "list") == 0) - { - print_rmgr_list(); - exit(EXIT_SUCCESS); - } - - for (i = 0; i <= RM_MAX_ID; i++) - { - if (pg_strcasecmp(optarg, RmgrDescTable[i].rm_name) == 0) - { - config.filter_by_rmgr = i; - break; - } - } - - if (config.filter_by_rmgr == -1) - { - fprintf(stderr, "%s: resource manager \"%s\" does not exist\n", - progname, optarg); - goto bad_argument; - } - } - break; - case 's': - if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2) - { - fprintf(stderr, "%s: could not parse start log position \"%s\"\n", - progname, optarg); - goto bad_argument; - } - else - private.startptr = (uint64) xlogid << 32 | xrecoff; - break; - case 't': - if (sscanf(optarg, "%d", &private.timeline) != 1) - { - fprintf(stderr, "%s: could not parse timeline \"%s\"\n", - progname, optarg); - goto bad_argument; - } - break; - case 'V': - puts("pg_xlogdump (PostgreSQL) " PG_VERSION); - exit(EXIT_SUCCESS); - break; - case 'x': - if (sscanf(optarg, "%u", &config.filter_by_xid) != 1) - { - fprintf(stderr, "%s: could not parse \"%s\" as a valid xid\n", - progname, optarg); - goto bad_argument; - } - config.filter_by_xid_enabled = true; - break; - case 'z': - config.stats = true; - config.stats_per_record = false; - if (optarg) - { - if (strcmp(optarg, "record") == 0) - config.stats_per_record = true; - else if (strcmp(optarg, "rmgr") != 0) - { - fprintf(stderr, "%s: unrecognised argument to --stats: %s\n", - progname, optarg); - goto bad_argument; - } - } - break; - default: - goto bad_argument; - } - } - - if ((optind + 2) < argc) - { - fprintf(stderr, - "%s: too many command-line arguments (first is \"%s\")\n", - progname, argv[optind + 2]); - goto bad_argument; - } - - if (private.inpath != NULL) - { - /* validate path points to directory */ - if (!verify_directory(private.inpath)) - { - fprintf(stderr, - "%s: path \"%s\" cannot be opened: %s", - progname, private.inpath, strerror(errno)); - goto bad_argument; - } - } - - /* parse files as start/end boundaries, extract path if not specified */ - if (optind < argc) - { - char *directory = NULL; - char *fname = NULL; - int fd; - XLogSegNo segno; - - split_path(argv[optind], &directory, &fname); - - if (private.inpath == NULL && directory != NULL) - { - private.inpath = directory; - - if (!verify_directory(private.inpath)) - fatal_error("cannot open directory \"%s\": %s", - private.inpath, strerror(errno)); - } - - fd = fuzzy_open_file(private.inpath, fname); - if (fd < 0) - fatal_error("could not open file \"%s\"", fname); - close(fd); - - /* parse position from file */ - XLogFromFileName(fname, &private.timeline, &segno); - - if (XLogRecPtrIsInvalid(private.startptr)) - XLogSegNoOffsetToRecPtr(segno, 0, private.startptr); - else if (!XLByteInSeg(private.startptr, segno)) - { - fprintf(stderr, - "%s: start log position %X/%X is not inside file \"%s\"\n", - progname, - (uint32) (private.startptr >> 32), - (uint32) private.startptr, - fname); - goto bad_argument; - } - - /* no second file specified, set end position */ - if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr)) - XLogSegNoOffsetToRecPtr(segno + 1, 0, private.endptr); - - /* parse ENDSEG if passed */ - if (optind + 1 < argc) - { - XLogSegNo endsegno; - - /* ignore directory, already have that */ - split_path(argv[optind + 1], &directory, &fname); - - fd = fuzzy_open_file(private.inpath, fname); - if (fd < 0) - fatal_error("could not open file \"%s\"", fname); - close(fd); - - /* parse position from file */ - XLogFromFileName(fname, &private.timeline, &endsegno); - - if (endsegno < segno) - fatal_error("ENDSEG %s is before STARTSEG %s", - argv[optind + 1], argv[optind]); - - if (XLogRecPtrIsInvalid(private.endptr)) - XLogSegNoOffsetToRecPtr(endsegno + 1, 0, private.endptr); - - /* set segno to endsegno for check of --end */ - segno = endsegno; - } - - - if (!XLByteInSeg(private.endptr, segno) && - private.endptr != (segno + 1) * XLogSegSize) - { - fprintf(stderr, - "%s: end log position %X/%X is not inside file \"%s\"\n", - progname, - (uint32) (private.endptr >> 32), - (uint32) private.endptr, - argv[argc - 1]); - goto bad_argument; - } - } - - /* we don't know what to print */ - if (XLogRecPtrIsInvalid(private.startptr)) - { - fprintf(stderr, "%s: no start log position given in range mode.\n", progname); - goto bad_argument; - } - - /* done with argument parsing, do the actual work */ - - /* we have everything we need, start reading */ - xlogreader_state = XLogReaderAllocate(XLogDumpReadPage, &private); - if (!xlogreader_state) - fatal_error("out of memory"); - - /* first find a valid recptr to start from */ - first_record = XLogFindNextRecord(xlogreader_state, private.startptr); - - if (first_record == InvalidXLogRecPtr) - fatal_error("could not find a valid record after %X/%X", - (uint32) (private.startptr >> 32), - (uint32) private.startptr); - - /* - * Display a message that we're skipping data if `from` wasn't a pointer - * to the start of a record and also wasn't a pointer to the beginning of - * a segment (e.g. we were used in file mode). - */ - if (first_record != private.startptr && (private.startptr % XLogSegSize) != 0) - printf("first record is after %X/%X, at %X/%X, skipping over %u bytes\n", - (uint32) (private.startptr >> 32), (uint32) private.startptr, - (uint32) (first_record >> 32), (uint32) first_record, - (uint32) (first_record - private.startptr)); - - for (;;) - { - /* try to read the next record */ - record = XLogReadRecord(xlogreader_state, first_record, &errormsg); - if (!record) - { - if (!config.follow || private.endptr_reached) - break; - else - { - pg_usleep(1000000L); /* 1 second */ - continue; - } - } - - /* after reading the first record, continue at next one */ - first_record = InvalidXLogRecPtr; - - /* apply all specified filters */ - if (config.filter_by_rmgr != -1 && - config.filter_by_rmgr != record->xl_rmid) - continue; - - if (config.filter_by_xid_enabled && - config.filter_by_xid != record->xl_xid) - continue; - - /* process the record */ - if (config.stats == true) - XLogDumpCountRecord(&config, &stats, xlogreader_state); - else - XLogDumpDisplayRecord(&config, xlogreader_state); - - /* check whether we printed enough */ - config.already_displayed_records++; - if (config.stop_after_records > 0 && - config.already_displayed_records >= config.stop_after_records) - break; - } - - if (config.stats == true) - XLogDumpDisplayStats(&config, &stats); - - if (errormsg) - fatal_error("error in WAL record at %X/%X: %s\n", - (uint32) (xlogreader_state->ReadRecPtr >> 32), - (uint32) xlogreader_state->ReadRecPtr, - errormsg); - - XLogReaderFree(xlogreader_state); - - return EXIT_SUCCESS; - -bad_argument: - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); - return EXIT_FAILURE; -} diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c deleted file mode 100644 index bd3344ccd6d..00000000000 --- a/contrib/pg_xlogdump/rmgrdesc.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * rmgrdesc.c - * - * pg_xlogdump resource managers definition - * - * contrib/pg_xlogdump/rmgrdesc.c - */ -#define FRONTEND 1 -#include "postgres.h" - -#include "access/brin_xlog.h" -#include "access/clog.h" -#include "access/commit_ts.h" -#include "access/gin.h" -#include "access/gist_private.h" -#include "access/hash.h" -#include "access/heapam_xlog.h" -#include "access/multixact.h" -#include "access/nbtree.h" -#include "access/rmgr.h" -#include "access/spgist.h" -#include "access/xact.h" -#include "access/xlog_internal.h" -#include "catalog/storage_xlog.h" -#include "commands/dbcommands_xlog.h" -#include "commands/sequence.h" -#include "commands/tablespace.h" -#include "rmgrdesc.h" -#include "storage/standby.h" -#include "utils/relmapper.h" - -#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \ - { name, desc, identify}, - -const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = { -#include "access/rmgrlist.h" -}; diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h deleted file mode 100644 index aec44183037..00000000000 --- a/contrib/pg_xlogdump/rmgrdesc.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * rmgrdesc.h - * - * pg_xlogdump resource managers declaration - * - * contrib/pg_xlogdump/rmgrdesc.h - */ -#ifndef RMGRDESC_H -#define RMGRDESC_H - -#include "lib/stringinfo.h" - -typedef struct RmgrDescData -{ - const char *rm_name; - void (*rm_desc) (StringInfo buf, XLogReaderState *record); - const char *(*rm_identify) (uint8 info); -} RmgrDescData; - -extern const RmgrDescData RmgrDescTable[]; - -#endif /* RMGRDESC_H */ |