diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
commit | 311bcfc6b3acdd6fd152798c7f287ddf74fa2a98 (patch) | |
tree | 0ec307299b1dada3701e42f4ca6eda57d708261e /src/backend/access/rmgrdesc/xlogdesc.c | |
parent | Initial commit. (diff) | |
download | postgresql-15-upstream.tar.xz postgresql-15-upstream.zip |
Adding upstream version 15.4.upstream/15.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/access/rmgrdesc/xlogdesc.c')
-rw-r--r-- | src/backend/access/rmgrdesc/xlogdesc.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c new file mode 100644 index 0000000..fefc563 --- /dev/null +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -0,0 +1,331 @@ +/*------------------------------------------------------------------------- + * + * xlogdesc.c + * rmgr descriptor routines for access/transam/xlog.c + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/access/rmgrdesc/xlogdesc.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/transam.h" +#include "access/xlog.h" +#include "access/xlog_internal.h" +#include "catalog/pg_control.h" +#include "utils/guc.h" +#include "utils/timestamp.h" + +/* + * GUC support + */ +const struct config_enum_entry wal_level_options[] = { + {"minimal", WAL_LEVEL_MINIMAL, false}, + {"replica", WAL_LEVEL_REPLICA, false}, + {"archive", WAL_LEVEL_REPLICA, true}, /* deprecated */ + {"hot_standby", WAL_LEVEL_REPLICA, true}, /* deprecated */ + {"logical", WAL_LEVEL_LOGICAL, false}, + {NULL, 0, false} +}; + +void +xlog_desc(StringInfo buf, XLogReaderState *record) +{ + char *rec = XLogRecGetData(record); + uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; + + if (info == XLOG_CHECKPOINT_SHUTDOWN || + info == XLOG_CHECKPOINT_ONLINE) + { + CheckPoint *checkpoint = (CheckPoint *) rec; + + appendStringInfo(buf, "redo %X/%X; " + "tli %u; prev tli %u; fpw %s; xid %u:%u; oid %u; multi %u; offset %u; " + "oldest xid %u in DB %u; oldest multi %u in DB %u; " + "oldest/newest commit timestamp xid: %u/%u; " + "oldest running xid %u; %s", + LSN_FORMAT_ARGS(checkpoint->redo), + checkpoint->ThisTimeLineID, + checkpoint->PrevTimeLineID, + checkpoint->fullPageWrites ? "true" : "false", + EpochFromFullTransactionId(checkpoint->nextXid), + XidFromFullTransactionId(checkpoint->nextXid), + checkpoint->nextOid, + checkpoint->nextMulti, + checkpoint->nextMultiOffset, + checkpoint->oldestXid, + checkpoint->oldestXidDB, + checkpoint->oldestMulti, + checkpoint->oldestMultiDB, + checkpoint->oldestCommitTsXid, + checkpoint->newestCommitTsXid, + checkpoint->oldestActiveXid, + (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online"); + } + else if (info == XLOG_NEXTOID) + { + Oid nextOid; + + memcpy(&nextOid, rec, sizeof(Oid)); + appendStringInfo(buf, "%u", nextOid); + } + else if (info == XLOG_RESTORE_POINT) + { + xl_restore_point *xlrec = (xl_restore_point *) rec; + + appendStringInfoString(buf, xlrec->rp_name); + } + else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT) + { + /* no further information to print */ + } + else if (info == XLOG_BACKUP_END) + { + XLogRecPtr startpoint; + + memcpy(&startpoint, rec, sizeof(XLogRecPtr)); + appendStringInfo(buf, "%X/%X", LSN_FORMAT_ARGS(startpoint)); + } + else if (info == XLOG_PARAMETER_CHANGE) + { + xl_parameter_change xlrec; + const char *wal_level_str; + const struct config_enum_entry *entry; + + memcpy(&xlrec, rec, sizeof(xl_parameter_change)); + + /* Find a string representation for wal_level */ + wal_level_str = "?"; + for (entry = wal_level_options; entry->name; entry++) + { + if (entry->val == xlrec.wal_level) + { + wal_level_str = entry->name; + break; + } + } + + appendStringInfo(buf, "max_connections=%d max_worker_processes=%d " + "max_wal_senders=%d max_prepared_xacts=%d " + "max_locks_per_xact=%d wal_level=%s " + "wal_log_hints=%s track_commit_timestamp=%s", + xlrec.MaxConnections, + xlrec.max_worker_processes, + xlrec.max_wal_senders, + xlrec.max_prepared_xacts, + xlrec.max_locks_per_xact, + wal_level_str, + xlrec.wal_log_hints ? "on" : "off", + xlrec.track_commit_timestamp ? "on" : "off"); + } + else if (info == XLOG_FPW_CHANGE) + { + bool fpw; + + memcpy(&fpw, rec, sizeof(bool)); + appendStringInfoString(buf, fpw ? "true" : "false"); + } + else if (info == XLOG_END_OF_RECOVERY) + { + xl_end_of_recovery xlrec; + + memcpy(&xlrec, rec, sizeof(xl_end_of_recovery)); + appendStringInfo(buf, "tli %u; prev tli %u; time %s", + xlrec.ThisTimeLineID, xlrec.PrevTimeLineID, + timestamptz_to_str(xlrec.end_time)); + } + else if (info == XLOG_OVERWRITE_CONTRECORD) + { + xl_overwrite_contrecord xlrec; + + memcpy(&xlrec, rec, sizeof(xl_overwrite_contrecord)); + appendStringInfo(buf, "lsn %X/%X; time %s", + LSN_FORMAT_ARGS(xlrec.overwritten_lsn), + timestamptz_to_str(xlrec.overwrite_time)); + } +} + +const char * +xlog_identify(uint8 info) +{ + const char *id = NULL; + + switch (info & ~XLR_INFO_MASK) + { + case XLOG_CHECKPOINT_SHUTDOWN: + id = "CHECKPOINT_SHUTDOWN"; + break; + case XLOG_CHECKPOINT_ONLINE: + id = "CHECKPOINT_ONLINE"; + break; + case XLOG_NOOP: + id = "NOOP"; + break; + case XLOG_NEXTOID: + id = "NEXTOID"; + break; + case XLOG_SWITCH: + id = "SWITCH"; + break; + case XLOG_BACKUP_END: + id = "BACKUP_END"; + break; + case XLOG_PARAMETER_CHANGE: + id = "PARAMETER_CHANGE"; + break; + case XLOG_RESTORE_POINT: + id = "RESTORE_POINT"; + break; + case XLOG_FPW_CHANGE: + id = "FPW_CHANGE"; + break; + case XLOG_END_OF_RECOVERY: + id = "END_OF_RECOVERY"; + break; + case XLOG_OVERWRITE_CONTRECORD: + id = "OVERWRITE_CONTRECORD"; + break; + case XLOG_FPI: + id = "FPI"; + break; + case XLOG_FPI_FOR_HINT: + id = "FPI_FOR_HINT"; + break; + } + + return id; +} + +/* + * Returns a string giving information about all the blocks in an + * XLogRecord. + */ +void +XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty, + bool detailed_format, StringInfo buf, + uint32 *fpi_len) +{ + int block_id; + + Assert(record != NULL); + + if (detailed_format && pretty) + appendStringInfoChar(buf, '\n'); + + for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++) + { + RelFileNode rnode; + ForkNumber forknum; + BlockNumber blk; + + if (!XLogRecGetBlockTagExtended(record, block_id, + &rnode, &forknum, &blk, NULL)) + continue; + + if (detailed_format) + { + /* Get block references in detailed format. */ + + if (pretty) + appendStringInfoChar(buf, '\t'); + else if (block_id > 0) + appendStringInfoChar(buf, ' '); + + appendStringInfo(buf, + "blkref #%d: rel %u/%u/%u fork %s blk %u", + block_id, + rnode.spcNode, rnode.dbNode, rnode.relNode, + forkNames[forknum], + blk); + + if (XLogRecHasBlockImage(record, block_id)) + { + uint8 bimg_info = XLogRecGetBlock(record, block_id)->bimg_info; + + /* Calculate the amount of FPI data in the record. */ + if (fpi_len) + *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len; + + if (BKPIMAGE_COMPRESSED(bimg_info)) + { + const char *method; + + if ((bimg_info & BKPIMAGE_COMPRESS_PGLZ) != 0) + method = "pglz"; + else if ((bimg_info & BKPIMAGE_COMPRESS_LZ4) != 0) + method = "lz4"; + else if ((bimg_info & BKPIMAGE_COMPRESS_ZSTD) != 0) + method = "zstd"; + else + method = "unknown"; + + appendStringInfo(buf, + " (FPW%s); hole: offset: %u, length: %u, " + "compression saved: %u, method: %s", + XLogRecBlockImageApply(record, block_id) ? + "" : " for WAL verification", + XLogRecGetBlock(record, block_id)->hole_offset, + XLogRecGetBlock(record, block_id)->hole_length, + BLCKSZ - + XLogRecGetBlock(record, block_id)->hole_length - + XLogRecGetBlock(record, block_id)->bimg_len, + method); + } + else + { + appendStringInfo(buf, + " (FPW%s); hole: offset: %u, length: %u", + XLogRecBlockImageApply(record, block_id) ? + "" : " for WAL verification", + XLogRecGetBlock(record, block_id)->hole_offset, + XLogRecGetBlock(record, block_id)->hole_length); + } + } + + if (pretty) + appendStringInfoChar(buf, '\n'); + } + else + { + /* Get block references in short format. */ + + if (forknum != MAIN_FORKNUM) + { + appendStringInfo(buf, + ", blkref #%d: rel %u/%u/%u fork %s blk %u", + block_id, + rnode.spcNode, rnode.dbNode, rnode.relNode, + forkNames[forknum], + blk); + } + else + { + appendStringInfo(buf, + ", blkref #%d: rel %u/%u/%u blk %u", + block_id, + rnode.spcNode, rnode.dbNode, rnode.relNode, + blk); + } + + if (XLogRecHasBlockImage(record, block_id)) + { + /* Calculate the amount of FPI data in the record. */ + if (fpi_len) + *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len; + + if (XLogRecBlockImageApply(record, block_id)) + appendStringInfo(buf, " FPW"); + else + appendStringInfo(buf, " FPW for WAL verification"); + } + } + } + + if (!detailed_format && pretty) + appendStringInfoChar(buf, '\n'); +} |