PostgreSQL Source Code  git master
heapdesc.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * heapdesc.c
4  * rmgr descriptor routines for access/heap/heapam.c
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/access/rmgrdesc/heapdesc.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/heapam_xlog.h"
18 #include "access/rmgrdesc_utils.h"
19 
20 /*
21  * NOTE: "keyname" argument cannot have trailing spaces or punctuation
22  * characters
23  */
24 static void
25 infobits_desc(StringInfo buf, uint8 infobits, const char *keyname)
26 {
27  appendStringInfo(buf, "%s: [", keyname);
28 
29  Assert(buf->data[buf->len - 1] != ' ');
30 
31  if (infobits & XLHL_XMAX_IS_MULTI)
32  appendStringInfoString(buf, "IS_MULTI, ");
33  if (infobits & XLHL_XMAX_LOCK_ONLY)
34  appendStringInfoString(buf, "LOCK_ONLY, ");
35  if (infobits & XLHL_XMAX_EXCL_LOCK)
36  appendStringInfoString(buf, "EXCL_LOCK, ");
37  if (infobits & XLHL_XMAX_KEYSHR_LOCK)
38  appendStringInfoString(buf, "KEYSHR_LOCK, ");
39  if (infobits & XLHL_KEYS_UPDATED)
40  appendStringInfoString(buf, "KEYS_UPDATED, ");
41 
42  if (buf->data[buf->len - 1] == ' ')
43  {
44  /* Truncate-away final unneeded ", " */
45  Assert(buf->data[buf->len - 2] == ',');
46  buf->len -= 2;
47  buf->data[buf->len] = '\0';
48  }
49 
51 }
52 
53 static void
55 {
56  appendStringInfoString(buf, "flags: [");
57 
58  if (flags & XLH_TRUNCATE_CASCADE)
59  appendStringInfoString(buf, "CASCADE, ");
60  if (flags & XLH_TRUNCATE_RESTART_SEQS)
61  appendStringInfoString(buf, "RESTART_SEQS, ");
62 
63  if (buf->data[buf->len - 1] == ' ')
64  {
65  /* Truncate-away final unneeded ", " */
66  Assert(buf->data[buf->len - 2] == ',');
67  buf->len -= 2;
68  buf->data[buf->len] = '\0';
69  }
70 
72 }
73 
74 static void
76 {
77  xlhp_freeze_plan *new_plan = (xlhp_freeze_plan *) plan;
78  OffsetNumber **offsets = data;
79 
80  appendStringInfo(buf, "{ xmax: %u, infomask: %u, infomask2: %u, ntuples: %u",
81  new_plan->xmax,
82  new_plan->t_infomask, new_plan->t_infomask2,
83  new_plan->ntuples);
84 
85  appendStringInfoString(buf, ", offsets:");
86  array_desc(buf, *offsets, sizeof(OffsetNumber), new_plan->ntuples,
87  &offset_elem_desc, NULL);
88 
89  *offsets += new_plan->ntuples;
90 
92 }
93 
94 
95 /*
96  * Given a MAXALIGNed buffer returned by XLogRecGetBlockData() and pointed to
97  * by cursor and any xl_heap_prune flags, deserialize the arrays of
98  * OffsetNumbers contained in an XLOG_HEAP2_PRUNE_* record.
99  *
100  * This is in heapdesc.c so it can be shared between heap2_redo and heap2_desc
101  * code, the latter of which is used in frontend (pg_waldump) code.
102  */
103 void
105  int *nplans, xlhp_freeze_plan **plans,
106  OffsetNumber **frz_offsets,
107  int *nredirected, OffsetNumber **redirected,
108  int *ndead, OffsetNumber **nowdead,
109  int *nunused, OffsetNumber **nowunused)
110 {
111  if (flags & XLHP_HAS_FREEZE_PLANS)
112  {
113  xlhp_freeze_plans *freeze_plans = (xlhp_freeze_plans *) cursor;
114 
115  *nplans = freeze_plans->nplans;
116  Assert(*nplans > 0);
117  *plans = freeze_plans->plans;
118 
119  cursor += offsetof(xlhp_freeze_plans, plans);
120  cursor += sizeof(xlhp_freeze_plan) * *nplans;
121  }
122  else
123  {
124  *nplans = 0;
125  *plans = NULL;
126  }
127 
128  if (flags & XLHP_HAS_REDIRECTIONS)
129  {
130  xlhp_prune_items *subrecord = (xlhp_prune_items *) cursor;
131 
132  *nredirected = subrecord->ntargets;
133  Assert(*nredirected > 0);
134  *redirected = &subrecord->data[0];
135 
136  cursor += offsetof(xlhp_prune_items, data);
137  cursor += sizeof(OffsetNumber[2]) * *nredirected;
138  }
139  else
140  {
141  *nredirected = 0;
142  *redirected = NULL;
143  }
144 
145  if (flags & XLHP_HAS_DEAD_ITEMS)
146  {
147  xlhp_prune_items *subrecord = (xlhp_prune_items *) cursor;
148 
149  *ndead = subrecord->ntargets;
150  Assert(*ndead > 0);
151  *nowdead = subrecord->data;
152 
153  cursor += offsetof(xlhp_prune_items, data);
154  cursor += sizeof(OffsetNumber) * *ndead;
155  }
156  else
157  {
158  *ndead = 0;
159  *nowdead = NULL;
160  }
161 
162  if (flags & XLHP_HAS_NOW_UNUSED_ITEMS)
163  {
164  xlhp_prune_items *subrecord = (xlhp_prune_items *) cursor;
165 
166  *nunused = subrecord->ntargets;
167  Assert(*nunused > 0);
168  *nowunused = subrecord->data;
169 
170  cursor += offsetof(xlhp_prune_items, data);
171  cursor += sizeof(OffsetNumber) * *nunused;
172  }
173  else
174  {
175  *nunused = 0;
176  *nowunused = NULL;
177  }
178 
179  *frz_offsets = (OffsetNumber *) cursor;
180 }
181 
182 void
184 {
185  char *rec = XLogRecGetData(record);
186  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
187 
188  info &= XLOG_HEAP_OPMASK;
189  if (info == XLOG_HEAP_INSERT)
190  {
191  xl_heap_insert *xlrec = (xl_heap_insert *) rec;
192 
193  appendStringInfo(buf, "off: %u, flags: 0x%02X",
194  xlrec->offnum,
195  xlrec->flags);
196  }
197  else if (info == XLOG_HEAP_DELETE)
198  {
199  xl_heap_delete *xlrec = (xl_heap_delete *) rec;
200 
201  appendStringInfo(buf, "xmax: %u, off: %u, ",
202  xlrec->xmax, xlrec->offnum);
203  infobits_desc(buf, xlrec->infobits_set, "infobits");
204  appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
205  }
206  else if (info == XLOG_HEAP_UPDATE)
207  {
208  xl_heap_update *xlrec = (xl_heap_update *) rec;
209 
210  appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
211  xlrec->old_xmax, xlrec->old_offnum);
212  infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
213  appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
214  xlrec->flags, xlrec->new_xmax, xlrec->new_offnum);
215  }
216  else if (info == XLOG_HEAP_HOT_UPDATE)
217  {
218  xl_heap_update *xlrec = (xl_heap_update *) rec;
219 
220  appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
221  xlrec->old_xmax, xlrec->old_offnum);
222  infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
223  appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
224  xlrec->flags, xlrec->new_xmax, xlrec->new_offnum);
225  }
226  else if (info == XLOG_HEAP_TRUNCATE)
227  {
228  xl_heap_truncate *xlrec = (xl_heap_truncate *) rec;
229 
230  truncate_flags_desc(buf, xlrec->flags);
231  appendStringInfo(buf, ", nrelids: %u", xlrec->nrelids);
232  appendStringInfoString(buf, ", relids:");
233  array_desc(buf, xlrec->relids, sizeof(Oid), xlrec->nrelids,
234  &oid_elem_desc, NULL);
235  }
236  else if (info == XLOG_HEAP_CONFIRM)
237  {
238  xl_heap_confirm *xlrec = (xl_heap_confirm *) rec;
239 
240  appendStringInfo(buf, "off: %u", xlrec->offnum);
241  }
242  else if (info == XLOG_HEAP_LOCK)
243  {
244  xl_heap_lock *xlrec = (xl_heap_lock *) rec;
245 
246  appendStringInfo(buf, "xmax: %u, off: %u, ",
247  xlrec->xmax, xlrec->offnum);
248  infobits_desc(buf, xlrec->infobits_set, "infobits");
249  appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
250  }
251  else if (info == XLOG_HEAP_INPLACE)
252  {
253  xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
254 
255  appendStringInfo(buf, "off: %u", xlrec->offnum);
256  }
257 }
258 
259 void
261 {
262  char *rec = XLogRecGetData(record);
263  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
264 
265  info &= XLOG_HEAP_OPMASK;
266  if (info == XLOG_HEAP2_PRUNE_ON_ACCESS ||
269  {
270  xl_heap_prune *xlrec = (xl_heap_prune *) rec;
271 
272  if (xlrec->flags & XLHP_HAS_CONFLICT_HORIZON)
273  {
274  TransactionId conflict_xid;
275 
276  memcpy(&conflict_xid, rec + SizeOfHeapPrune, sizeof(TransactionId));
277 
278  appendStringInfo(buf, "snapshotConflictHorizon: %u",
279  conflict_xid);
280  }
281 
282  appendStringInfo(buf, ", isCatalogRel: %c",
283  xlrec->flags & XLHP_IS_CATALOG_REL ? 'T' : 'F');
284 
285  if (XLogRecHasBlockData(record, 0))
286  {
287  Size datalen;
288  OffsetNumber *redirected;
289  OffsetNumber *nowdead;
290  OffsetNumber *nowunused;
291  int nredirected;
292  int nunused;
293  int ndead;
294  int nplans;
295  xlhp_freeze_plan *plans;
296  OffsetNumber *frz_offsets;
297 
298  char *cursor = XLogRecGetBlockData(record, 0, &datalen);
299 
301  &nplans, &plans, &frz_offsets,
302  &nredirected, &redirected,
303  &ndead, &nowdead,
304  &nunused, &nowunused);
305 
306  appendStringInfo(buf, ", nplans: %u, nredirected: %u, ndead: %u, nunused: %u",
307  nplans, nredirected, ndead, nunused);
308 
309  if (nplans > 0)
310  {
311  appendStringInfoString(buf, ", plans:");
312  array_desc(buf, plans, sizeof(xlhp_freeze_plan), nplans,
313  &plan_elem_desc, &frz_offsets);
314  }
315 
316  if (nredirected > 0)
317  {
318  appendStringInfoString(buf, ", redirected:");
319  array_desc(buf, redirected, sizeof(OffsetNumber) * 2,
320  nredirected, &redirect_elem_desc, NULL);
321  }
322 
323  if (ndead > 0)
324  {
325  appendStringInfoString(buf, ", dead:");
326  array_desc(buf, nowdead, sizeof(OffsetNumber), ndead,
327  &offset_elem_desc, NULL);
328  }
329 
330  if (nunused > 0)
331  {
332  appendStringInfoString(buf, ", unused:");
333  array_desc(buf, nowunused, sizeof(OffsetNumber), nunused,
334  &offset_elem_desc, NULL);
335  }
336  }
337  }
338  else if (info == XLOG_HEAP2_VISIBLE)
339  {
340  xl_heap_visible *xlrec = (xl_heap_visible *) rec;
341 
342  appendStringInfo(buf, "snapshotConflictHorizon: %u, flags: 0x%02X",
343  xlrec->snapshotConflictHorizon, xlrec->flags);
344  }
345  else if (info == XLOG_HEAP2_MULTI_INSERT)
346  {
348  bool isinit = (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE) != 0;
349 
350  appendStringInfo(buf, "ntuples: %d, flags: 0x%02X", xlrec->ntuples,
351  xlrec->flags);
352 
353  if (XLogRecHasBlockData(record, 0) && !isinit)
354  {
355  appendStringInfoString(buf, ", offsets:");
356  array_desc(buf, xlrec->offsets, sizeof(OffsetNumber),
357  xlrec->ntuples, &offset_elem_desc, NULL);
358  }
359  }
360  else if (info == XLOG_HEAP2_LOCK_UPDATED)
361  {
363 
364  appendStringInfo(buf, "xmax: %u, off: %u, ",
365  xlrec->xmax, xlrec->offnum);
366  infobits_desc(buf, xlrec->infobits_set, "infobits");
367  appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
368  }
369  else if (info == XLOG_HEAP2_NEW_CID)
370  {
371  xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec;
372 
373  appendStringInfo(buf, "rel: %u/%u/%u, tid: %u/%u",
374  xlrec->target_locator.spcOid,
375  xlrec->target_locator.dbOid,
376  xlrec->target_locator.relNumber,
379  appendStringInfo(buf, ", cmin: %u, cmax: %u, combo: %u",
380  xlrec->cmin, xlrec->cmax, xlrec->combocid);
381  }
382 }
383 
384 const char *
386 {
387  const char *id = NULL;
388 
389  switch (info & ~XLR_INFO_MASK)
390  {
391  case XLOG_HEAP_INSERT:
392  id = "INSERT";
393  break;
395  id = "INSERT+INIT";
396  break;
397  case XLOG_HEAP_DELETE:
398  id = "DELETE";
399  break;
400  case XLOG_HEAP_UPDATE:
401  id = "UPDATE";
402  break;
404  id = "UPDATE+INIT";
405  break;
407  id = "HOT_UPDATE";
408  break;
410  id = "HOT_UPDATE+INIT";
411  break;
412  case XLOG_HEAP_TRUNCATE:
413  id = "TRUNCATE";
414  break;
415  case XLOG_HEAP_CONFIRM:
416  id = "HEAP_CONFIRM";
417  break;
418  case XLOG_HEAP_LOCK:
419  id = "LOCK";
420  break;
421  case XLOG_HEAP_INPLACE:
422  id = "INPLACE";
423  break;
424  }
425 
426  return id;
427 }
428 
429 const char *
431 {
432  const char *id = NULL;
433 
434  switch (info & ~XLR_INFO_MASK)
435  {
437  id = "PRUNE_ON_ACCESS";
438  break;
440  id = "PRUNE_VACUUM_SCAN";
441  break;
443  id = "PRUNE_VACUUM_CLEANUP";
444  break;
445  case XLOG_HEAP2_VISIBLE:
446  id = "VISIBLE";
447  break;
449  id = "MULTI_INSERT";
450  break;
452  id = "MULTI_INSERT+INIT";
453  break;
455  id = "LOCK_UPDATED";
456  break;
457  case XLOG_HEAP2_NEW_CID:
458  id = "NEW_CID";
459  break;
460  case XLOG_HEAP2_REWRITE:
461  id = "REWRITE";
462  break;
463  }
464 
465  return id;
466 }
#define Assert(condition)
Definition: c.h:858
unsigned char uint8
Definition: c.h:504
uint32 TransactionId
Definition: c.h:652
size_t Size
Definition: c.h:605
struct xlhp_freeze_plan xlhp_freeze_plan
#define XLOG_HEAP2_MULTI_INSERT
Definition: heapam_xlog.h:63
#define XLOG_HEAP_HOT_UPDATE
Definition: heapam_xlog.h:36
#define XLOG_HEAP_DELETE
Definition: heapam_xlog.h:33
#define XLHP_HAS_CONFLICT_HORIZON
Definition: heapam_xlog.h:316
#define XLOG_HEAP2_REWRITE
Definition: heapam_xlog.h:58
#define XLHP_HAS_FREEZE_PLANS
Definition: heapam_xlog.h:322
#define XLOG_HEAP_TRUNCATE
Definition: heapam_xlog.h:35
#define XLOG_HEAP_OPMASK
Definition: heapam_xlog.h:41
#define XLH_TRUNCATE_RESTART_SEQS
Definition: heapam_xlog.h:126
#define XLOG_HEAP_UPDATE
Definition: heapam_xlog.h:34
#define SizeOfHeapPrune
Definition: heapam_xlog.h:295
#define XLHL_XMAX_KEYSHR_LOCK
Definition: heapam_xlog.h:388
#define XLHP_HAS_NOW_UNUSED_ITEMS
Definition: heapam_xlog.h:331
#define XLHL_XMAX_IS_MULTI
Definition: heapam_xlog.h:385
#define XLHP_HAS_REDIRECTIONS
Definition: heapam_xlog.h:329
#define XLOG_HEAP2_PRUNE_VACUUM_SCAN
Definition: heapam_xlog.h:60
#define XLHL_XMAX_LOCK_ONLY
Definition: heapam_xlog.h:386
#define XLOG_HEAP_INPLACE
Definition: heapam_xlog.h:39
#define XLOG_HEAP2_LOCK_UPDATED
Definition: heapam_xlog.h:64
#define XLHL_XMAX_EXCL_LOCK
Definition: heapam_xlog.h:387
#define XLOG_HEAP2_PRUNE_ON_ACCESS
Definition: heapam_xlog.h:59
#define XLOG_HEAP2_NEW_CID
Definition: heapam_xlog.h:65
#define XLHP_HAS_DEAD_ITEMS
Definition: heapam_xlog.h:330
#define XLOG_HEAP_LOCK
Definition: heapam_xlog.h:38
#define XLOG_HEAP2_PRUNE_VACUUM_CLEANUP
Definition: heapam_xlog.h:61
#define XLH_TRUNCATE_CASCADE
Definition: heapam_xlog.h:125
#define XLOG_HEAP_INSERT
Definition: heapam_xlog.h:32
#define XLHL_KEYS_UPDATED
Definition: heapam_xlog.h:389
#define XLOG_HEAP2_VISIBLE
Definition: heapam_xlog.h:62
#define XLHP_IS_CATALOG_REL
Definition: heapam_xlog.h:298
#define XLOG_HEAP_INIT_PAGE
Definition: heapam_xlog.h:46
#define XLOG_HEAP_CONFIRM
Definition: heapam_xlog.h:37
void heap_desc(StringInfo buf, XLogReaderState *record)
Definition: heapdesc.c:183
const char * heap_identify(uint8 info)
Definition: heapdesc.c:385
void heap2_desc(StringInfo buf, XLogReaderState *record)
Definition: heapdesc.c:260
void heap_xlog_deserialize_prune_and_freeze(char *cursor, uint8 flags, int *nplans, xlhp_freeze_plan **plans, OffsetNumber **frz_offsets, int *nredirected, OffsetNumber **redirected, int *ndead, OffsetNumber **nowdead, int *nunused, OffsetNumber **nowunused)
Definition: heapdesc.c:104
static void plan_elem_desc(StringInfo buf, void *plan, void *data)
Definition: heapdesc.c:75
const char * heap2_identify(uint8 info)
Definition: heapdesc.c:430
static void truncate_flags_desc(StringInfo buf, uint8 flags)
Definition: heapdesc.c:54
static void infobits_desc(StringInfo buf, uint8 infobits, const char *keyname)
Definition: heapdesc.c:25
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition: itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103
uint16 OffsetNumber
Definition: off.h:24
const void * data
#define plan(x)
Definition: pg_regress.c:162
static char * buf
Definition: pg_test_fsync.c:73
unsigned int Oid
Definition: postgres_ext.h:31
void oid_elem_desc(StringInfo buf, void *relid, void *data)
void redirect_elem_desc(StringInfo buf, void *offset, void *data)
void array_desc(StringInfo buf, void *array, size_t elem_size, int count, void(*elem_desc)(StringInfo buf, void *elem, void *data), void *data)
void offset_elem_desc(StringInfo buf, void *offset, void *data)
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
RelFileNumber relNumber
Definition: type.h:137
OffsetNumber offnum
Definition: heapam_xlog.h:419
TransactionId xmax
Definition: heapam_xlog.h:114
OffsetNumber offnum
Definition: heapam_xlog.h:115
uint8 infobits_set
Definition: heapam_xlog.h:116
OffsetNumber offnum
Definition: heapam_xlog.h:427
OffsetNumber offnum
Definition: heapam_xlog.h:161
TransactionId xmax
Definition: heapam_xlog.h:408
OffsetNumber offnum
Definition: heapam_xlog.h:409
uint8 infobits_set
Definition: heapam_xlog.h:399
OffsetNumber offnum
Definition: heapam_xlog.h:398
TransactionId xmax
Definition: heapam_xlog.h:397
OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]
Definition: heapam_xlog.h:184
CommandId cmin
Definition: heapam_xlog.h:454
CommandId combocid
Definition: heapam_xlog.h:456
ItemPointerData target_tid
Definition: heapam_xlog.h:462
CommandId cmax
Definition: heapam_xlog.h:455
RelFileLocator target_locator
Definition: heapam_xlog.h:461
Oid relids[FLEXIBLE_ARRAY_MEMBER]
Definition: heapam_xlog.h:138
TransactionId new_xmax
Definition: heapam_xlog.h:223
uint8 old_infobits_set
Definition: heapam_xlog.h:221
TransactionId old_xmax
Definition: heapam_xlog.h:219
OffsetNumber old_offnum
Definition: heapam_xlog.h:220
OffsetNumber new_offnum
Definition: heapam_xlog.h:224
TransactionId snapshotConflictHorizon
Definition: heapam_xlog.h:441
TransactionId xmax
Definition: heapam_xlog.h:343
xlhp_freeze_plan plans[FLEXIBLE_ARRAY_MEMBER]
Definition: heapam_xlog.h:367
OffsetNumber data[FLEXIBLE_ARRAY_MEMBER]
Definition: heapam_xlog.h:380
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:2025
#define XLogRecHasBlockData(decoder, block_id)
Definition: xlogreader.h:427
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define XLR_INFO_MASK
Definition: xlogrecord.h:62