diff options
-rw-r--r-- | doc/src/sgml/pgwalinspect.sgml | 22 | ||||
-rw-r--r-- | src/backend/access/rmgrdesc/Makefile | 1 | ||||
-rw-r--r-- | src/backend/access/rmgrdesc/heapdesc.c | 155 | ||||
-rw-r--r-- | src/backend/access/rmgrdesc/meson.build | 1 | ||||
-rw-r--r-- | src/backend/access/rmgrdesc/rmgrdesc_utils.c | 84 | ||||
-rw-r--r-- | src/bin/pg_waldump/Makefile | 2 | ||||
-rw-r--r-- | src/include/access/rmgrdesc_utils.h | 22 |
7 files changed, 247 insertions, 40 deletions
diff --git a/doc/src/sgml/pgwalinspect.sgml b/doc/src/sgml/pgwalinspect.sgml index d9ed8f0a9a4..b3712be0097 100644 --- a/doc/src/sgml/pgwalinspect.sgml +++ b/doc/src/sgml/pgwalinspect.sgml @@ -71,19 +71,19 @@ after the <replaceable>in_lsn</replaceable> argument. For example: <screen> -postgres=# SELECT * FROM pg_get_wal_record_info('0/1E826E98'); --[ RECORD 1 ]----+---------------------------------------------------- -start_lsn | 0/1E826F20 -end_lsn | 0/1E826F60 -prev_lsn | 0/1E826C80 +postgres=# SELECT * FROM pg_get_wal_record_info('0/E84F5E8'); +-[ RECORD 1 ]----+-------------------------------------------------- +start_lsn | 0/E84F5E8 +end_lsn | 0/E84F620 +prev_lsn | 0/E84F5A8 xid | 0 resource_manager | Heap2 -record_type | PRUNE -record_length | 58 -main_data_length | 8 +record_type | VACUUM +record_length | 50 +main_data_length | 2 fpi_length | 0 -description | snapshotConflictHorizon 33748 nredirected 0 ndead 2 -block_ref | blkref #0: rel 1663/5/60221 fork main blk 2 +description | nunused: 1, unused: [ 22 ] +block_ref | blkref #0: rel 1663/16389/20884 fork main blk 126 </screen> </para> <para> @@ -144,7 +144,7 @@ block_ref | references. Returns one row per block reference per WAL record. For example: <screen> -postgres=# SELECT * FROM pg_get_wal_block_info('0/10E9D80', '0/10E9DC0') LIMIT 1; +postgres=# SELECT * FROM pg_get_wal_block_info('0/10E9D80', '0/10E9DC0'); -[ RECORD 1 ]-----+----------------------------------- start_lsn | 0/10E9D80 end_lsn | 0/10E9DC0 diff --git a/src/backend/access/rmgrdesc/Makefile b/src/backend/access/rmgrdesc/Makefile index f88d72fd862..cd95eec37f1 100644 --- a/src/backend/access/rmgrdesc/Makefile +++ b/src/backend/access/rmgrdesc/Makefile @@ -23,6 +23,7 @@ OBJS = \ nbtdesc.o \ relmapdesc.o \ replorigindesc.o \ + rmgrdesc_utils.o \ seqdesc.o \ smgrdesc.o \ spgdesc.o \ diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c index 628f7e82156..6dfd7d7d130 100644 --- a/src/backend/access/rmgrdesc/heapdesc.c +++ b/src/backend/access/rmgrdesc/heapdesc.c @@ -15,20 +15,52 @@ #include "postgres.h" #include "access/heapam_xlog.h" +#include "access/rmgrdesc_utils.h" static void out_infobits(StringInfo buf, uint8 infobits) { + if ((infobits & XLHL_XMAX_IS_MULTI) == 0 && + (infobits & XLHL_XMAX_LOCK_ONLY) == 0 && + (infobits & XLHL_XMAX_EXCL_LOCK) == 0 && + (infobits & XLHL_XMAX_KEYSHR_LOCK) == 0 && + (infobits & XLHL_KEYS_UPDATED) == 0) + return; + + appendStringInfoString(buf, ", infobits: ["); + if (infobits & XLHL_XMAX_IS_MULTI) - appendStringInfoString(buf, "IS_MULTI "); + appendStringInfoString(buf, " IS_MULTI"); if (infobits & XLHL_XMAX_LOCK_ONLY) - appendStringInfoString(buf, "LOCK_ONLY "); + appendStringInfoString(buf, ", LOCK_ONLY"); if (infobits & XLHL_XMAX_EXCL_LOCK) - appendStringInfoString(buf, "EXCL_LOCK "); + appendStringInfoString(buf, ", EXCL_LOCK"); if (infobits & XLHL_XMAX_KEYSHR_LOCK) - appendStringInfoString(buf, "KEYSHR_LOCK "); + appendStringInfoString(buf, ", KEYSHR_LOCK"); if (infobits & XLHL_KEYS_UPDATED) - appendStringInfoString(buf, "KEYS_UPDATED "); + appendStringInfoString(buf, ", KEYS_UPDATED"); + + appendStringInfoString(buf, " ]"); +} + +static void +plan_elem_desc(StringInfo buf, void *plan, void *data) +{ + xl_heap_freeze_plan *new_plan = (xl_heap_freeze_plan *) plan; + OffsetNumber **offsets = data; + + appendStringInfo(buf, "{ xmax: %u, infomask: %u, infomask2: %u, ntuples: %u", + new_plan->xmax, + new_plan->t_infomask, new_plan->t_infomask2, + new_plan->ntuples); + + appendStringInfoString(buf, ", offsets:"); + array_desc(buf, *offsets, sizeof(OffsetNumber), new_plan->ntuples, + &offset_elem_desc, NULL); + + *offsets += new_plan->ntuples; + + appendStringInfo(buf, " }"); } void @@ -42,14 +74,15 @@ heap_desc(StringInfo buf, XLogReaderState *record) { xl_heap_insert *xlrec = (xl_heap_insert *) rec; - appendStringInfo(buf, "off %u flags 0x%02X", xlrec->offnum, + appendStringInfo(buf, "off: %u, flags: 0x%02X", + xlrec->offnum, xlrec->flags); } else if (info == XLOG_HEAP_DELETE) { xl_heap_delete *xlrec = (xl_heap_delete *) rec; - appendStringInfo(buf, "off %u flags 0x%02X ", + appendStringInfo(buf, "off: %u, flags: 0x%02X", xlrec->offnum, xlrec->flags); out_infobits(buf, xlrec->infobits_set); @@ -58,12 +91,12 @@ heap_desc(StringInfo buf, XLogReaderState *record) { xl_heap_update *xlrec = (xl_heap_update *) rec; - appendStringInfo(buf, "off %u xmax %u flags 0x%02X ", + appendStringInfo(buf, "off: %u, xmax: %u, flags: 0x%02X", xlrec->old_offnum, xlrec->old_xmax, xlrec->flags); out_infobits(buf, xlrec->old_infobits_set); - appendStringInfo(buf, "; new off %u xmax %u", + appendStringInfo(buf, ", new off: %u, xmax %u", xlrec->new_offnum, xlrec->new_xmax); } @@ -71,39 +104,42 @@ heap_desc(StringInfo buf, XLogReaderState *record) { xl_heap_update *xlrec = (xl_heap_update *) rec; - appendStringInfo(buf, "off %u xmax %u flags 0x%02X ", + appendStringInfo(buf, "off: %u, xmax: %u, flags: 0x%02X", xlrec->old_offnum, xlrec->old_xmax, xlrec->flags); out_infobits(buf, xlrec->old_infobits_set); - appendStringInfo(buf, "; new off %u xmax %u", + appendStringInfo(buf, ", new off: %u, xmax: %u", xlrec->new_offnum, xlrec->new_xmax); } else if (info == XLOG_HEAP_TRUNCATE) { xl_heap_truncate *xlrec = (xl_heap_truncate *) rec; - int i; + appendStringInfoString(buf, "flags: ["); if (xlrec->flags & XLH_TRUNCATE_CASCADE) - appendStringInfoString(buf, "cascade "); + appendStringInfoString(buf, " CASCADE"); if (xlrec->flags & XLH_TRUNCATE_RESTART_SEQS) - appendStringInfoString(buf, "restart_seqs "); - appendStringInfo(buf, "nrelids %u relids", xlrec->nrelids); - for (i = 0; i < xlrec->nrelids; i++) - appendStringInfo(buf, " %u", xlrec->relids[i]); + appendStringInfoString(buf, ", RESTART_SEQS"); + appendStringInfoString(buf, " ]"); + + appendStringInfo(buf, ", nrelids: %u", xlrec->nrelids); + appendStringInfoString(buf, ", relids:"); + array_desc(buf, xlrec->relids, sizeof(Oid), xlrec->nrelids, + &relid_desc, NULL); } else if (info == XLOG_HEAP_CONFIRM) { xl_heap_confirm *xlrec = (xl_heap_confirm *) rec; - appendStringInfo(buf, "off %u", xlrec->offnum); + appendStringInfo(buf, "off: %u", xlrec->offnum); } else if (info == XLOG_HEAP_LOCK) { xl_heap_lock *xlrec = (xl_heap_lock *) rec; - appendStringInfo(buf, "off %u: xid %u: flags 0x%02X ", + appendStringInfo(buf, "off: %u, xid: %u, flags: 0x%02X", xlrec->offnum, xlrec->locking_xid, xlrec->flags); out_infobits(buf, xlrec->infobits_set); } @@ -111,9 +147,10 @@ heap_desc(StringInfo buf, XLogReaderState *record) { xl_heap_inplace *xlrec = (xl_heap_inplace *) rec; - appendStringInfo(buf, "off %u", xlrec->offnum); + appendStringInfo(buf, "off: %u", xlrec->offnum); } } + void heap2_desc(StringInfo buf, XLogReaderState *record) { @@ -125,43 +162,105 @@ heap2_desc(StringInfo buf, XLogReaderState *record) { xl_heap_prune *xlrec = (xl_heap_prune *) rec; - appendStringInfo(buf, "snapshotConflictHorizon %u nredirected %u ndead %u", + appendStringInfo(buf, "snapshotConflictHorizon: %u, nredirected: %u, ndead: %u", xlrec->snapshotConflictHorizon, xlrec->nredirected, xlrec->ndead); + + if (!XLogRecHasBlockImage(record, 0)) + { + OffsetNumber *end; + OffsetNumber *redirected; + OffsetNumber *nowdead; + OffsetNumber *nowunused; + int nredirected; + int nunused; + Size datalen; + + redirected = (OffsetNumber *) XLogRecGetBlockData(record, 0, + &datalen); + + nredirected = xlrec->nredirected; + end = (OffsetNumber *) ((char *) redirected + datalen); + nowdead = redirected + (nredirected * 2); + nowunused = nowdead + xlrec->ndead; + nunused = (end - nowunused); + Assert(nunused >= 0); + + appendStringInfo(buf, ", nunused: %u", nunused); + + appendStringInfoString(buf, ", redirected:"); + array_desc(buf, redirected, sizeof(OffsetNumber) * 2, + nredirected, &redirect_elem_desc, NULL); + appendStringInfoString(buf, ", dead:"); + array_desc(buf, nowdead, sizeof(OffsetNumber), xlrec->ndead, + &offset_elem_desc, NULL); + appendStringInfoString(buf, ", unused:"); + array_desc(buf, nowunused, sizeof(OffsetNumber), nunused, + &offset_elem_desc, NULL); + } } else if (info == XLOG_HEAP2_VACUUM) { xl_heap_vacuum *xlrec = (xl_heap_vacuum *) rec; - appendStringInfo(buf, "nunused %u", xlrec->nunused); + appendStringInfo(buf, "nunused: %u", xlrec->nunused); + + if (!XLogRecHasBlockImage(record, 0)) + { + OffsetNumber *nowunused; + + nowunused = (OffsetNumber *) XLogRecGetBlockData(record, 0, NULL); + + appendStringInfoString(buf, ", unused:"); + array_desc(buf, nowunused, sizeof(OffsetNumber), xlrec->nunused, + &offset_elem_desc, NULL); + } } else if (info == XLOG_HEAP2_FREEZE_PAGE) { xl_heap_freeze_page *xlrec = (xl_heap_freeze_page *) rec; - appendStringInfo(buf, "snapshotConflictHorizon %u nplans %u", + appendStringInfo(buf, "snapshotConflictHorizon: %u, nplans: %u", xlrec->snapshotConflictHorizon, xlrec->nplans); + + if (!XLogRecHasBlockImage(record, 0)) + { + xl_heap_freeze_plan *plans; + OffsetNumber *offsets; + + plans = (xl_heap_freeze_plan *) XLogRecGetBlockData(record, 0, NULL); + offsets = (OffsetNumber *) &plans[xlrec->nplans]; + appendStringInfoString(buf, ", plans:"); + array_desc(buf, plans, sizeof(xl_heap_freeze_plan), xlrec->nplans, + &plan_elem_desc, &offsets); + } } else if (info == XLOG_HEAP2_VISIBLE) { xl_heap_visible *xlrec = (xl_heap_visible *) rec; - appendStringInfo(buf, "snapshotConflictHorizon %u flags 0x%02X", + appendStringInfo(buf, "snapshotConflictHorizon: %u, flags: 0x%02X", xlrec->snapshotConflictHorizon, xlrec->flags); } else if (info == XLOG_HEAP2_MULTI_INSERT) { xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec; + bool isinit = (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE) != 0; - appendStringInfo(buf, "%d tuples flags 0x%02X", xlrec->ntuples, + appendStringInfo(buf, "ntuples: %d, flags: 0x%02X", xlrec->ntuples, xlrec->flags); + + appendStringInfoString(buf, ", offsets:"); + if (!XLogRecHasBlockImage(record, 0) && !isinit) + array_desc(buf, xlrec->offsets, sizeof(OffsetNumber), + xlrec->ntuples, &offset_elem_desc, NULL); } else if (info == XLOG_HEAP2_LOCK_UPDATED) { xl_heap_lock_updated *xlrec = (xl_heap_lock_updated *) rec; - appendStringInfo(buf, "off %u: xmax %u: flags 0x%02X ", + appendStringInfo(buf, "off: %u, xmax: %u, flags: 0x%02X", xlrec->offnum, xlrec->xmax, xlrec->flags); out_infobits(buf, xlrec->infobits_set); } @@ -169,13 +268,13 @@ heap2_desc(StringInfo buf, XLogReaderState *record) { xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec; - appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u", + appendStringInfo(buf, "rel: %u/%u/%u, tid: %u/%u", xlrec->target_locator.spcOid, xlrec->target_locator.dbOid, xlrec->target_locator.relNumber, ItemPointerGetBlockNumber(&(xlrec->target_tid)), ItemPointerGetOffsetNumber(&(xlrec->target_tid))); - appendStringInfo(buf, "; cmin: %u, cmax: %u, combo: %u", + appendStringInfo(buf, ", cmin: %u, cmax: %u, combo: %u", xlrec->cmin, xlrec->cmax, xlrec->combocid); } } diff --git a/src/backend/access/rmgrdesc/meson.build b/src/backend/access/rmgrdesc/meson.build index 166cee67b6e..f76e87e2d7d 100644 --- a/src/backend/access/rmgrdesc/meson.build +++ b/src/backend/access/rmgrdesc/meson.build @@ -16,6 +16,7 @@ rmgr_desc_sources = files( 'nbtdesc.c', 'relmapdesc.c', 'replorigindesc.c', + 'rmgrdesc_utils.c', 'seqdesc.c', 'smgrdesc.c', 'spgdesc.c', diff --git a/src/backend/access/rmgrdesc/rmgrdesc_utils.c b/src/backend/access/rmgrdesc/rmgrdesc_utils.c new file mode 100644 index 00000000000..180f64bf84b --- /dev/null +++ b/src/backend/access/rmgrdesc/rmgrdesc_utils.c @@ -0,0 +1,84 @@ +/*------------------------------------------------------------------------- + * + * rmgrdesc_utils.c + * Support functions for rmgrdesc routines + * + * Copyright (c) 2023, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/backend/access/rmgrdesc/rmgrdesc_utils.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/rmgrdesc_utils.h" +#include "storage/off.h" + +/* + * Guidelines for formatting desc functions: + * + * member1_name: member1_value, member2_name: member2_value + * + * If the value is a list, please use: + * + * member3_name: [ member3_list_value1, member3_list_value2 ] + * + * The first item appended to the string should not be prepended by any spaces + * or comma, however all subsequent appends to the string are responsible for + * prepending themselves with a comma followed by a space. + * + * Arrays should have a space between the opening square bracket and first + * element and between the last element and closing brace. + * + * Flags should be in ALL CAPS. + * + * For lists/arrays of items, the number of those items should be listed at + * the beginning with all of the other numbers. + * + * List punctuation should still be included even if there are 0 items. + * + * Composite objects in a list should be surrounded with { }. + */ +void +array_desc(StringInfo buf, void *array, size_t elem_size, int count, + void (*elem_desc) (StringInfo buf, void *elem, void *data), + void *data) +{ + if (count == 0) + { + appendStringInfoString(buf, " []"); + return; + } + appendStringInfo(buf, " ["); + for (int i = 0; i < count; i++) + { + if (i > 0) + appendStringInfoString(buf, ","); + appendStringInfoString(buf, " "); + + elem_desc(buf, (char *) array + elem_size * i, data); + } + appendStringInfoString(buf, " ]"); +} + +void +offset_elem_desc(StringInfo buf, void *offset, void *data) +{ + appendStringInfo(buf, "%u", *(OffsetNumber *) offset); +} + +void +redirect_elem_desc(StringInfo buf, void *offset, void *data) +{ + OffsetNumber *new_offset = (OffsetNumber *) offset; + + appendStringInfo(buf, "%u->%u", new_offset[0], new_offset[1]); +} + +void +relid_desc(StringInfo buf, void *relid, void *data) +{ + appendStringInfo(buf, "%u", *(Oid *) relid); +} diff --git a/src/bin/pg_waldump/Makefile b/src/bin/pg_waldump/Makefile index d6459e17c73..0ecf582039d 100644 --- a/src/bin/pg_waldump/Makefile +++ b/src/bin/pg_waldump/Makefile @@ -18,7 +18,7 @@ OBJS = \ override CPPFLAGS := -DFRONTEND $(CPPFLAGS) -RMGRDESCSOURCES = $(sort $(notdir $(wildcard $(top_srcdir)/src/backend/access/rmgrdesc/*desc.c))) +RMGRDESCSOURCES = $(sort $(notdir $(wildcard $(top_srcdir)/src/backend/access/rmgrdesc/*desc*.c))) RMGRDESCOBJS = $(patsubst %.c,%.o,$(RMGRDESCSOURCES)) diff --git a/src/include/access/rmgrdesc_utils.h b/src/include/access/rmgrdesc_utils.h new file mode 100644 index 00000000000..aa6d0290d9c --- /dev/null +++ b/src/include/access/rmgrdesc_utils.h @@ -0,0 +1,22 @@ +/*------------------------------------------------------------------------- + * + * rmgrdesc_utils.h + * Support functions for rmgrdesc routines + * + * Copyright (c) 2023, PostgreSQL Global Development Group + * + * src/include/access/rmgrdesc_utils.h + * + *------------------------------------------------------------------------- + */ +#ifndef RMGRDESC_UTILS_H_ +#define RMGRDESC_UTILS_H_ + +extern void array_desc(StringInfo buf, void *array, size_t elem_size, int count, + void (*elem_desc) (StringInfo buf, void *elem, void *data), + void *data); +extern void offset_elem_desc(StringInfo buf, void *offset, void *data); +extern void redirect_elem_desc(StringInfo buf, void *offset, void *data); +extern void relid_desc(StringInfo buf, void *relid, void *data); + +#endif /* RMGRDESC_UTILS_H */ |