1 /*-------------------------------------------------------------------------
4 * rmgr descriptor routines for access/heap/heapam.c
6 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/access/rmgrdesc/heapdesc.c
13 *-------------------------------------------------------------------------
17 #include "access/heapam_xlog.h"
18 #include "access/rmgrdesc_utils.h"
21 * NOTE: "keyname" argument cannot have trailing spaces or punctuation
25 infobits_desc(StringInfo buf
, uint8 infobits
, const char *keyname
)
27 appendStringInfo(buf
, "%s: [", keyname
);
29 Assert(buf
->data
[buf
->len
- 1] != ' ');
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, ");
42 if (buf
->data
[buf
->len
- 1] == ' ')
44 /* Truncate-away final unneeded ", " */
45 Assert(buf
->data
[buf
->len
- 2] == ',');
47 buf
->data
[buf
->len
] = '\0';
50 appendStringInfoString(buf
, "]");
54 truncate_flags_desc(StringInfo buf
, uint8 flags
)
56 appendStringInfoString(buf
, "flags: [");
58 if (flags
& XLH_TRUNCATE_CASCADE
)
59 appendStringInfoString(buf
, "CASCADE, ");
60 if (flags
& XLH_TRUNCATE_RESTART_SEQS
)
61 appendStringInfoString(buf
, "RESTART_SEQS, ");
63 if (buf
->data
[buf
->len
- 1] == ' ')
65 /* Truncate-away final unneeded ", " */
66 Assert(buf
->data
[buf
->len
- 2] == ',');
68 buf
->data
[buf
->len
] = '\0';
71 appendStringInfoString(buf
, "]");
75 plan_elem_desc(StringInfo buf
, void *plan
, void *data
)
77 xl_heap_freeze_plan
*new_plan
= (xl_heap_freeze_plan
*) plan
;
78 OffsetNumber
**offsets
= data
;
80 appendStringInfo(buf
, "{ xmax: %u, infomask: %u, infomask2: %u, ntuples: %u",
82 new_plan
->t_infomask
, new_plan
->t_infomask2
,
85 appendStringInfoString(buf
, ", offsets:");
86 array_desc(buf
, *offsets
, sizeof(OffsetNumber
), new_plan
->ntuples
,
87 &offset_elem_desc
, NULL
);
89 *offsets
+= new_plan
->ntuples
;
91 appendStringInfo(buf
, " }");
95 heap_desc(StringInfo buf
, XLogReaderState
*record
)
97 char *rec
= XLogRecGetData(record
);
98 uint8 info
= XLogRecGetInfo(record
) & ~XLR_INFO_MASK
;
100 info
&= XLOG_HEAP_OPMASK
;
101 if (info
== XLOG_HEAP_INSERT
)
103 xl_heap_insert
*xlrec
= (xl_heap_insert
*) rec
;
105 appendStringInfo(buf
, "off: %u, flags: 0x%02X",
109 else if (info
== XLOG_HEAP_DELETE
)
111 xl_heap_delete
*xlrec
= (xl_heap_delete
*) rec
;
113 appendStringInfo(buf
, "xmax: %u, off: %u, ",
114 xlrec
->xmax
, xlrec
->offnum
);
115 infobits_desc(buf
, xlrec
->infobits_set
, "infobits");
116 appendStringInfo(buf
, ", flags: 0x%02X", xlrec
->flags
);
118 else if (info
== XLOG_HEAP_UPDATE
)
120 xl_heap_update
*xlrec
= (xl_heap_update
*) rec
;
122 appendStringInfo(buf
, "old_xmax: %u, old_off: %u, ",
123 xlrec
->old_xmax
, xlrec
->old_offnum
);
124 infobits_desc(buf
, xlrec
->old_infobits_set
, "old_infobits");
125 appendStringInfo(buf
, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
126 xlrec
->flags
, xlrec
->new_xmax
, xlrec
->new_offnum
);
128 else if (info
== XLOG_HEAP_HOT_UPDATE
)
130 xl_heap_update
*xlrec
= (xl_heap_update
*) rec
;
132 appendStringInfo(buf
, "old_xmax: %u, old_off: %u, ",
133 xlrec
->old_xmax
, xlrec
->old_offnum
);
134 infobits_desc(buf
, xlrec
->old_infobits_set
, "old_infobits");
135 appendStringInfo(buf
, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
136 xlrec
->flags
, xlrec
->new_xmax
, xlrec
->new_offnum
);
138 else if (info
== XLOG_HEAP_TRUNCATE
)
140 xl_heap_truncate
*xlrec
= (xl_heap_truncate
*) rec
;
142 truncate_flags_desc(buf
, xlrec
->flags
);
143 appendStringInfo(buf
, ", nrelids: %u", xlrec
->nrelids
);
144 appendStringInfoString(buf
, ", relids:");
145 array_desc(buf
, xlrec
->relids
, sizeof(Oid
), xlrec
->nrelids
,
146 &oid_elem_desc
, NULL
);
148 else if (info
== XLOG_HEAP_CONFIRM
)
150 xl_heap_confirm
*xlrec
= (xl_heap_confirm
*) rec
;
152 appendStringInfo(buf
, "off: %u", xlrec
->offnum
);
154 else if (info
== XLOG_HEAP_LOCK
)
156 xl_heap_lock
*xlrec
= (xl_heap_lock
*) rec
;
158 appendStringInfo(buf
, "xmax: %u, off: %u, ",
159 xlrec
->xmax
, xlrec
->offnum
);
160 infobits_desc(buf
, xlrec
->infobits_set
, "infobits");
161 appendStringInfo(buf
, ", flags: 0x%02X", xlrec
->flags
);
163 else if (info
== XLOG_HEAP_INPLACE
)
165 xl_heap_inplace
*xlrec
= (xl_heap_inplace
*) rec
;
167 appendStringInfo(buf
, "off: %u", xlrec
->offnum
);
172 heap2_desc(StringInfo buf
, XLogReaderState
*record
)
174 char *rec
= XLogRecGetData(record
);
175 uint8 info
= XLogRecGetInfo(record
) & ~XLR_INFO_MASK
;
177 info
&= XLOG_HEAP_OPMASK
;
178 if (info
== XLOG_HEAP2_PRUNE
)
180 xl_heap_prune
*xlrec
= (xl_heap_prune
*) rec
;
182 appendStringInfo(buf
, "snapshotConflictHorizon: %u, nredirected: %u, ndead: %u",
183 xlrec
->snapshotConflictHorizon
,
187 if (!XLogRecHasBlockImage(record
, 0))
190 OffsetNumber
*redirected
;
191 OffsetNumber
*nowdead
;
192 OffsetNumber
*nowunused
;
197 redirected
= (OffsetNumber
*) XLogRecGetBlockData(record
, 0,
200 nredirected
= xlrec
->nredirected
;
201 end
= (OffsetNumber
*) ((char *) redirected
+ datalen
);
202 nowdead
= redirected
+ (nredirected
* 2);
203 nowunused
= nowdead
+ xlrec
->ndead
;
204 nunused
= (end
- nowunused
);
205 Assert(nunused
>= 0);
207 appendStringInfo(buf
, ", nunused: %u", nunused
);
209 appendStringInfoString(buf
, ", redirected:");
210 array_desc(buf
, redirected
, sizeof(OffsetNumber
) * 2,
211 nredirected
, &redirect_elem_desc
, NULL
);
212 appendStringInfoString(buf
, ", dead:");
213 array_desc(buf
, nowdead
, sizeof(OffsetNumber
), xlrec
->ndead
,
214 &offset_elem_desc
, NULL
);
215 appendStringInfoString(buf
, ", unused:");
216 array_desc(buf
, nowunused
, sizeof(OffsetNumber
), nunused
,
217 &offset_elem_desc
, NULL
);
220 else if (info
== XLOG_HEAP2_VACUUM
)
222 xl_heap_vacuum
*xlrec
= (xl_heap_vacuum
*) rec
;
224 appendStringInfo(buf
, "nunused: %u", xlrec
->nunused
);
226 if (!XLogRecHasBlockImage(record
, 0))
228 OffsetNumber
*nowunused
;
230 nowunused
= (OffsetNumber
*) XLogRecGetBlockData(record
, 0, NULL
);
232 appendStringInfoString(buf
, ", unused:");
233 array_desc(buf
, nowunused
, sizeof(OffsetNumber
), xlrec
->nunused
,
234 &offset_elem_desc
, NULL
);
237 else if (info
== XLOG_HEAP2_FREEZE_PAGE
)
239 xl_heap_freeze_page
*xlrec
= (xl_heap_freeze_page
*) rec
;
241 appendStringInfo(buf
, "snapshotConflictHorizon: %u, nplans: %u",
242 xlrec
->snapshotConflictHorizon
, xlrec
->nplans
);
244 if (!XLogRecHasBlockImage(record
, 0))
246 xl_heap_freeze_plan
*plans
;
247 OffsetNumber
*offsets
;
249 plans
= (xl_heap_freeze_plan
*) XLogRecGetBlockData(record
, 0, NULL
);
250 offsets
= (OffsetNumber
*) ((char *) plans
+
252 sizeof(xl_heap_freeze_plan
)));
253 appendStringInfoString(buf
, ", plans:");
254 array_desc(buf
, plans
, sizeof(xl_heap_freeze_plan
), xlrec
->nplans
,
255 &plan_elem_desc
, &offsets
);
258 else if (info
== XLOG_HEAP2_VISIBLE
)
260 xl_heap_visible
*xlrec
= (xl_heap_visible
*) rec
;
262 appendStringInfo(buf
, "snapshotConflictHorizon: %u, flags: 0x%02X",
263 xlrec
->snapshotConflictHorizon
, xlrec
->flags
);
265 else if (info
== XLOG_HEAP2_MULTI_INSERT
)
267 xl_heap_multi_insert
*xlrec
= (xl_heap_multi_insert
*) rec
;
268 bool isinit
= (XLogRecGetInfo(record
) & XLOG_HEAP_INIT_PAGE
) != 0;
270 appendStringInfo(buf
, "ntuples: %d, flags: 0x%02X", xlrec
->ntuples
,
273 if (!XLogRecHasBlockImage(record
, 0) && !isinit
)
275 appendStringInfoString(buf
, ", offsets:");
276 array_desc(buf
, xlrec
->offsets
, sizeof(OffsetNumber
),
277 xlrec
->ntuples
, &offset_elem_desc
, NULL
);
280 else if (info
== XLOG_HEAP2_LOCK_UPDATED
)
282 xl_heap_lock_updated
*xlrec
= (xl_heap_lock_updated
*) rec
;
284 appendStringInfo(buf
, "xmax: %u, off: %u, ",
285 xlrec
->xmax
, xlrec
->offnum
);
286 infobits_desc(buf
, xlrec
->infobits_set
, "infobits");
287 appendStringInfo(buf
, ", flags: 0x%02X", xlrec
->flags
);
289 else if (info
== XLOG_HEAP2_NEW_CID
)
291 xl_heap_new_cid
*xlrec
= (xl_heap_new_cid
*) rec
;
293 appendStringInfo(buf
, "rel: %u/%u/%u, tid: %u/%u",
294 xlrec
->target_locator
.spcOid
,
295 xlrec
->target_locator
.dbOid
,
296 xlrec
->target_locator
.relNumber
,
297 ItemPointerGetBlockNumber(&(xlrec
->target_tid
)),
298 ItemPointerGetOffsetNumber(&(xlrec
->target_tid
)));
299 appendStringInfo(buf
, ", cmin: %u, cmax: %u, combo: %u",
300 xlrec
->cmin
, xlrec
->cmax
, xlrec
->combocid
);
305 heap_identify(uint8 info
)
307 const char *id
= NULL
;
309 switch (info
& ~XLR_INFO_MASK
)
311 case XLOG_HEAP_INSERT
:
314 case XLOG_HEAP_INSERT
| XLOG_HEAP_INIT_PAGE
:
317 case XLOG_HEAP_DELETE
:
320 case XLOG_HEAP_UPDATE
:
323 case XLOG_HEAP_UPDATE
| XLOG_HEAP_INIT_PAGE
:
326 case XLOG_HEAP_HOT_UPDATE
:
329 case XLOG_HEAP_HOT_UPDATE
| XLOG_HEAP_INIT_PAGE
:
330 id
= "HOT_UPDATE+INIT";
332 case XLOG_HEAP_TRUNCATE
:
335 case XLOG_HEAP_CONFIRM
:
341 case XLOG_HEAP_INPLACE
:
350 heap2_identify(uint8 info
)
352 const char *id
= NULL
;
354 switch (info
& ~XLR_INFO_MASK
)
356 case XLOG_HEAP2_PRUNE
:
359 case XLOG_HEAP2_VACUUM
:
362 case XLOG_HEAP2_FREEZE_PAGE
:
365 case XLOG_HEAP2_VISIBLE
:
368 case XLOG_HEAP2_MULTI_INSERT
:
371 case XLOG_HEAP2_MULTI_INSERT
| XLOG_HEAP_INIT_PAGE
:
372 id
= "MULTI_INSERT+INIT";
374 case XLOG_HEAP2_LOCK_UPDATED
:
377 case XLOG_HEAP2_NEW_CID
:
380 case XLOG_HEAP2_REWRITE
: