Fix nbtree posting list update desc output.

We cannot use the generic array_desc approach with per-tuple nbtree
posting list update metadata because array_desc can only deal with fixed
width elements (e.g., page offset numbers).  Using array_desc led to
incorrect rmgr descriptions for updates from nbtree DELETE/VACUUM WAL
records.

To fix, add specialized code to describe the update metadata as array
elements in desc output.  We now iterate over the update metadata using
an approach that matches related REDO routines.

Also stop showing the updates offset number array separately in nbtree
DELETE/VACUUM desc output.  It's redundant information, since the same
page offset numbers appear in the description of each individual update
element.  Also make some small tweaks to the way that we format arrays
in all desc routines (not just nbtree desc routines) to make arrays a
little less verbose.

Oversight in commit 1c453cfd, which enhanced the nbtree rmgr desc
routines.

Author: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/CAH2-WzkbYuvwYKm-Y-72QEh6SPMQcAo9uONv+mR3bMGcu9E_Cg@mail.gmail.com
This commit is contained in:
Peter Geoghegan 2023-04-10 11:15:41 -07:00
parent fbbd7edca8
commit 5d6728e588
5 changed files with 87 additions and 98 deletions

View File

@ -71,19 +71,19 @@
after the <replaceable>in_lsn</replaceable> argument. For after the <replaceable>in_lsn</replaceable> argument. For
example: example:
<screen> <screen>
postgres=# SELECT * FROM pg_get_wal_record_info('0/E84F5E8'); postgres=# SELECT * FROM pg_get_wal_record_info('0/E419E28');
-[ RECORD 1 ]----+-------------------------------------------------- -[ RECORD 1 ]----+-------------------------------------------------
start_lsn | 0/E84F5E8 start_lsn | 0/E419E28
end_lsn | 0/E84F620 end_lsn | 0/E419E68
prev_lsn | 0/E84F5A8 prev_lsn | 0/E419D78
xid | 0 xid | 0
resource_manager | Heap2 resource_manager | Heap2
record_type | VACUUM record_type | VACUUM
record_length | 50 record_length | 58
main_data_length | 2 main_data_length | 2
fpi_length | 0 fpi_length | 0
description | nunused: 1, unused: [ 22 ] description | nunused: 5, unused: [1, 2, 3, 4, 5]
block_ref | blkref #0: rel 1663/16389/20884 fork main blk 126 block_ref | blkref #0: rel 1663/16385/1249 fork main blk 364
</screen> </screen>
</para> </para>
<para> <para>
@ -144,18 +144,18 @@ block_ref |
references. Returns one row per block reference per WAL record. references. Returns one row per block reference per WAL record.
For example: For example:
<screen> <screen>
postgres=# SELECT * FROM pg_get_wal_block_info('0/10E9D80', '0/10E9DC0'); postgres=# SELECT * FROM pg_get_wal_block_info('0/1230278', '0/12302B8');
-[ RECORD 1 ]-----+----------------------------------- -[ RECORD 1 ]-----+-----------------------------------
start_lsn | 0/10E9D80 start_lsn | 0/1230278
end_lsn | 0/10E9DC0 end_lsn | 0/12302B8
prev_lsn | 0/10E9860 prev_lsn | 0/122FD40
block_id | 0 block_id | 0
reltablespace | 1663 reltablespace | 1663
reldatabase | 1 reldatabase | 1
relfilenode | 2690 relfilenode | 2658
relforknumber | 0 relforknumber | 0
relblocknumber | 5 relblocknumber | 11
xid | 117 xid | 341
resource_manager | Btree resource_manager | Btree
record_type | INSERT_LEAF record_type | INSERT_LEAF
record_length | 64 record_length | 64
@ -163,8 +163,8 @@ main_data_length | 2
block_data_length | 16 block_data_length | 16
block_fpi_length | 0 block_fpi_length | 0
block_fpi_info | block_fpi_info |
description | off 14 description | off: 46
block_data | \x00005400020010001407000000000000 block_data | \x00002a00070010402630000070696400
block_fpi_data | block_fpi_data |
</screen> </screen>
</para> </para>

View File

@ -127,7 +127,7 @@ heap_desc(StringInfo buf, XLogReaderState *record)
appendStringInfo(buf, ", nrelids: %u", xlrec->nrelids); appendStringInfo(buf, ", nrelids: %u", xlrec->nrelids);
appendStringInfoString(buf, ", relids:"); appendStringInfoString(buf, ", relids:");
array_desc(buf, xlrec->relids, sizeof(Oid), xlrec->nrelids, array_desc(buf, xlrec->relids, sizeof(Oid), xlrec->nrelids,
&relid_desc, NULL); &oid_elem_desc, NULL);
} }
else if (info == XLOG_HEAP_CONFIRM) else if (info == XLOG_HEAP_CONFIRM)
{ {

View File

@ -17,59 +17,8 @@
#include "access/nbtxlog.h" #include "access/nbtxlog.h"
#include "access/rmgrdesc_utils.h" #include "access/rmgrdesc_utils.h"
static void btree_del_desc(StringInfo buf, char *block_data, uint16 ndeleted, static void delvacuum_desc(StringInfo buf, char *block_data,
uint16 nupdated); uint16 ndeleted, uint16 nupdated);
static void btree_update_elem_desc(StringInfo buf, void *update, void *data);
static void
btree_del_desc(StringInfo buf, char *block_data, uint16 ndeleted,
uint16 nupdated)
{
OffsetNumber *updatedoffsets;
xl_btree_update *updates;
OffsetNumber *data = (OffsetNumber *) block_data;
appendStringInfoString(buf, ", deleted:");
array_desc(buf, data, sizeof(OffsetNumber), ndeleted,
&offset_elem_desc, NULL);
appendStringInfoString(buf, ", updated:");
array_desc(buf, data, sizeof(OffsetNumber), nupdated,
&offset_elem_desc, NULL);
if (nupdated <= 0)
return;
updatedoffsets = (OffsetNumber *)
((char *) data + ndeleted * sizeof(OffsetNumber));
updates = (xl_btree_update *) ((char *) updatedoffsets +
nupdated *
sizeof(OffsetNumber));
appendStringInfoString(buf, ", updates:");
array_desc(buf, updates, sizeof(xl_btree_update),
nupdated, &btree_update_elem_desc,
&updatedoffsets);
}
static void
btree_update_elem_desc(StringInfo buf, void *update, void *data)
{
xl_btree_update *new_update = (xl_btree_update *) update;
OffsetNumber *updated_offset = *((OffsetNumber **) data);
appendStringInfo(buf, "{ updated offset: %u, ndeleted tids: %u",
*updated_offset, new_update->ndeletedtids);
appendStringInfoString(buf, ", deleted tids:");
array_desc(buf, (char *) new_update + SizeOfBtreeUpdate, sizeof(uint16),
new_update->ndeletedtids, &uint16_elem_desc, NULL);
updated_offset++;
appendStringInfo(buf, " }");
}
void void
btree_desc(StringInfo buf, XLogReaderState *record) btree_desc(StringInfo buf, XLogReaderState *record)
@ -114,9 +63,8 @@ btree_desc(StringInfo buf, XLogReaderState *record)
xlrec->ndeleted, xlrec->nupdated); xlrec->ndeleted, xlrec->nupdated);
if (!XLogRecHasBlockImage(record, 0)) if (!XLogRecHasBlockImage(record, 0))
btree_del_desc(buf, XLogRecGetBlockData(record, 0, NULL), delvacuum_desc(buf, XLogRecGetBlockData(record, 0, NULL),
xlrec->ndeleted, xlrec->nupdated); xlrec->ndeleted, xlrec->nupdated);
break; break;
} }
case XLOG_BTREE_DELETE: case XLOG_BTREE_DELETE:
@ -128,16 +76,15 @@ btree_desc(StringInfo buf, XLogReaderState *record)
xlrec->ndeleted, xlrec->nupdated); xlrec->ndeleted, xlrec->nupdated);
if (!XLogRecHasBlockImage(record, 0)) if (!XLogRecHasBlockImage(record, 0))
btree_del_desc(buf, XLogRecGetBlockData(record, 0, NULL), delvacuum_desc(buf, XLogRecGetBlockData(record, 0, NULL),
xlrec->ndeleted, xlrec->nupdated); xlrec->ndeleted, xlrec->nupdated);
break; break;
} }
case XLOG_BTREE_MARK_PAGE_HALFDEAD: case XLOG_BTREE_MARK_PAGE_HALFDEAD:
{ {
xl_btree_mark_page_halfdead *xlrec = (xl_btree_mark_page_halfdead *) rec; xl_btree_mark_page_halfdead *xlrec = (xl_btree_mark_page_halfdead *) rec;
appendStringInfo(buf, "topparent: %u; leaf: %u; left: %u; right: %u", appendStringInfo(buf, "topparent: %u, leaf: %u, left: %u, right: %u",
xlrec->topparent, xlrec->leafblk, xlrec->leftblk, xlrec->rightblk); xlrec->topparent, xlrec->leafblk, xlrec->leftblk, xlrec->rightblk);
break; break;
} }
@ -146,11 +93,11 @@ btree_desc(StringInfo buf, XLogReaderState *record)
{ {
xl_btree_unlink_page *xlrec = (xl_btree_unlink_page *) rec; xl_btree_unlink_page *xlrec = (xl_btree_unlink_page *) rec;
appendStringInfo(buf, "left: %u; right: %u; level: %u; safexid: %u:%u; ", appendStringInfo(buf, "left: %u, right: %u, level: %u, safexid: %u:%u, ",
xlrec->leftsib, xlrec->rightsib, xlrec->level, xlrec->leftsib, xlrec->rightsib, xlrec->level,
EpochFromFullTransactionId(xlrec->safexid), EpochFromFullTransactionId(xlrec->safexid),
XidFromFullTransactionId(xlrec->safexid)); XidFromFullTransactionId(xlrec->safexid));
appendStringInfo(buf, "leafleft: %u; leafright: %u; leaftopparent: %u", appendStringInfo(buf, "leafleft: %u, leafright: %u, leaftopparent: %u",
xlrec->leafleftsib, xlrec->leafrightsib, xlrec->leafleftsib, xlrec->leafrightsib,
xlrec->leaftopparent); xlrec->leaftopparent);
break; break;
@ -242,3 +189,59 @@ btree_identify(uint8 info)
return id; return id;
} }
static void
delvacuum_desc(StringInfo buf, char *block_data,
uint16 ndeleted, uint16 nupdated)
{
OffsetNumber *deletedoffsets;
OffsetNumber *updatedoffsets;
xl_btree_update *updates;
/* Output deleted page offset number array */
appendStringInfoString(buf, ", deleted:");
deletedoffsets = (OffsetNumber *) block_data;
array_desc(buf, deletedoffsets, sizeof(OffsetNumber), ndeleted,
&offset_elem_desc, NULL);
/*
* Output updates as an array of "update objects", where each element
* contains a page offset number from updated array. (This is not the
* most literal representation of the underlying physical data structure
* that we could use. Readability seems more important here.)
*/
appendStringInfoString(buf, ", updated: [");
updatedoffsets = (OffsetNumber *) (block_data + ndeleted *
sizeof(OffsetNumber));
updates = (xl_btree_update *) ((char *) updatedoffsets +
nupdated *
sizeof(OffsetNumber));
for (int i = 0; i < nupdated; i++)
{
OffsetNumber off = updatedoffsets[i];
Assert(OffsetNumberIsValid(off));
Assert(updates->ndeletedtids > 0);
appendStringInfo(buf, "{ off: %u, nptids: %u, ptids: [",
off, updates->ndeletedtids);
for (int p = 0; p < updates->ndeletedtids; p++)
{
uint16 *ptid;
ptid = (uint16 *) ((char *) updates + SizeOfBtreeUpdate) + p;
appendStringInfo(buf, "%u", *ptid);
if (p < updates->ndeletedtids - 1)
appendStringInfoString(buf, ", ");
}
appendStringInfoString(buf, "] }");
if (i < nupdated - 1)
appendStringInfoString(buf, ", ");
updates = (xl_btree_update *)
((char *) updates + SizeOfBtreeUpdate +
updates->ndeletedtids * sizeof(uint16));
}
appendStringInfoString(buf, "]");
}

View File

@ -29,16 +29,11 @@
* or comma, however all subsequent appends to the string are responsible for * or comma, however all subsequent appends to the string are responsible for
* prepending themselves with a comma followed by a space. * 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. * Flags should be in ALL CAPS.
* *
* For lists/arrays of items, the number of those items should be listed at * For lists/arrays of items, the number of those items should be listed at
* the beginning with all of the other numbers. * 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 { }. * Composite objects in a list should be surrounded with { }.
*/ */
void void
@ -51,16 +46,14 @@ array_desc(StringInfo buf, void *array, size_t elem_size, int count,
appendStringInfoString(buf, " []"); appendStringInfoString(buf, " []");
return; return;
} }
appendStringInfo(buf, " ["); appendStringInfoString(buf, " [");
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
if (i > 0)
appendStringInfoString(buf, ",");
appendStringInfoString(buf, " ");
elem_desc(buf, (char *) array + elem_size * i, data); elem_desc(buf, (char *) array + elem_size * i, data);
if (i < count - 1)
appendStringInfoString(buf, ", ");
} }
appendStringInfoString(buf, " ]"); appendStringInfoString(buf, "]");
} }
void void
@ -78,13 +71,7 @@ redirect_elem_desc(StringInfo buf, void *offset, void *data)
} }
void void
relid_desc(StringInfo buf, void *relid, void *data) oid_elem_desc(StringInfo buf, void *relid, void *data)
{ {
appendStringInfo(buf, "%u", *(Oid *) relid); appendStringInfo(buf, "%u", *(Oid *) relid);
} }
void
uint16_elem_desc(StringInfo buf, void *value, void *data)
{
appendStringInfo(buf, "%u", *(uint16 *) value);
}

View File

@ -17,7 +17,6 @@ extern void array_desc(StringInfo buf, void *array, size_t elem_size, int count,
void *data); void *data);
extern void offset_elem_desc(StringInfo buf, void *offset, 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 redirect_elem_desc(StringInfo buf, void *offset, void *data);
extern void relid_desc(StringInfo buf, void *relid, void *data); extern void oid_elem_desc(StringInfo buf, void *relid, void *data);
extern void uint16_elem_desc(StringInfo buf, void *value, void *data);
#endif /* RMGRDESC_UTILS_H */ #endif /* RMGRDESC_UTILS_H */