Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * heapdesc.c
4 : * rmgr descriptor routines for access/heap/heapam.c
5 : *
6 : * Portions Copyright (c) 1996-2023, 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 78 : infobits_desc(StringInfo buf, uint8 infobits, const char *keyname)
26 : {
27 78 : appendStringInfo(buf, "%s: [", keyname);
28 :
29 : Assert(buf->data[buf->len - 1] != ' ');
30 :
31 78 : if (infobits & XLHL_XMAX_IS_MULTI)
32 0 : appendStringInfoString(buf, "IS_MULTI, ");
33 78 : if (infobits & XLHL_XMAX_LOCK_ONLY)
34 16 : appendStringInfoString(buf, "LOCK_ONLY, ");
35 78 : if (infobits & XLHL_XMAX_EXCL_LOCK)
36 16 : appendStringInfoString(buf, "EXCL_LOCK, ");
37 78 : if (infobits & XLHL_XMAX_KEYSHR_LOCK)
38 0 : appendStringInfoString(buf, "KEYSHR_LOCK, ");
39 78 : if (infobits & XLHL_KEYS_UPDATED)
40 16 : appendStringInfoString(buf, "KEYS_UPDATED, ");
41 :
42 78 : if (buf->data[buf->len - 1] == ' ')
43 : {
44 : /* Truncate-away final unneeded ", " */
45 : Assert(buf->data[buf->len - 2] == ',');
46 32 : buf->len -= 2;
47 32 : buf->data[buf->len] = '\0';
48 : }
49 :
50 78 : appendStringInfoString(buf, "]");
51 78 : }
52 :
53 : static void
54 0 : truncate_flags_desc(StringInfo buf, uint8 flags)
55 : {
56 0 : appendStringInfoString(buf, "flags: [");
57 :
58 0 : if (flags & XLH_TRUNCATE_CASCADE)
59 0 : appendStringInfoString(buf, "CASCADE, ");
60 0 : if (flags & XLH_TRUNCATE_RESTART_SEQS)
61 0 : appendStringInfoString(buf, "RESTART_SEQS, ");
62 :
63 0 : if (buf->data[buf->len - 1] == ' ')
64 : {
65 : /* Truncate-away final unneeded ", " */
66 : Assert(buf->data[buf->len - 2] == ',');
67 0 : buf->len -= 2;
68 0 : buf->data[buf->len] = '\0';
69 : }
70 :
71 0 : appendStringInfoString(buf, "]");
72 0 : }
73 :
74 : static void
75 0 : plan_elem_desc(StringInfo buf, void *plan, void *data)
76 : {
77 0 : xl_heap_freeze_plan *new_plan = (xl_heap_freeze_plan *) plan;
78 0 : OffsetNumber **offsets = data;
79 :
80 0 : appendStringInfo(buf, "{ xmax: %u, infomask: %u, infomask2: %u, ntuples: %u",
81 : new_plan->xmax,
82 0 : new_plan->t_infomask, new_plan->t_infomask2,
83 0 : new_plan->ntuples);
84 :
85 0 : appendStringInfoString(buf, ", offsets:");
86 0 : array_desc(buf, *offsets, sizeof(OffsetNumber), new_plan->ntuples,
87 : &offset_elem_desc, NULL);
88 :
89 0 : *offsets += new_plan->ntuples;
90 :
91 0 : appendStringInfo(buf, " }");
92 0 : }
93 :
94 : void
95 61870 : heap_desc(StringInfo buf, XLogReaderState *record)
96 : {
97 61870 : char *rec = XLogRecGetData(record);
98 61870 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
99 :
100 61870 : info &= XLOG_HEAP_OPMASK;
101 61870 : if (info == XLOG_HEAP_INSERT)
102 : {
103 61792 : xl_heap_insert *xlrec = (xl_heap_insert *) rec;
104 :
105 61792 : appendStringInfo(buf, "off: %u, flags: 0x%02X",
106 61792 : xlrec->offnum,
107 61792 : xlrec->flags);
108 : }
109 78 : else if (info == XLOG_HEAP_DELETE)
110 : {
111 16 : xl_heap_delete *xlrec = (xl_heap_delete *) rec;
112 :
113 16 : appendStringInfo(buf, "xmax: %u, off: %u, ",
114 16 : xlrec->xmax, xlrec->offnum);
115 16 : infobits_desc(buf, xlrec->infobits_set, "infobits");
116 16 : appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
117 : }
118 62 : else if (info == XLOG_HEAP_UPDATE)
119 : {
120 16 : xl_heap_update *xlrec = (xl_heap_update *) rec;
121 :
122 16 : appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
123 16 : xlrec->old_xmax, xlrec->old_offnum);
124 16 : infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
125 16 : appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
126 16 : xlrec->flags, xlrec->new_xmax, xlrec->new_offnum);
127 : }
128 46 : else if (info == XLOG_HEAP_HOT_UPDATE)
129 : {
130 30 : xl_heap_update *xlrec = (xl_heap_update *) rec;
131 :
132 30 : appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
133 30 : xlrec->old_xmax, xlrec->old_offnum);
134 30 : infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
135 30 : appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
136 30 : xlrec->flags, xlrec->new_xmax, xlrec->new_offnum);
137 : }
138 16 : else if (info == XLOG_HEAP_TRUNCATE)
139 : {
140 0 : xl_heap_truncate *xlrec = (xl_heap_truncate *) rec;
141 :
142 0 : truncate_flags_desc(buf, xlrec->flags);
143 0 : appendStringInfo(buf, ", nrelids: %u", xlrec->nrelids);
144 0 : appendStringInfoString(buf, ", relids:");
145 0 : array_desc(buf, xlrec->relids, sizeof(Oid), xlrec->nrelids,
146 : &oid_elem_desc, NULL);
147 : }
148 16 : else if (info == XLOG_HEAP_CONFIRM)
149 : {
150 0 : xl_heap_confirm *xlrec = (xl_heap_confirm *) rec;
151 :
152 0 : appendStringInfo(buf, "off: %u", xlrec->offnum);
153 : }
154 16 : else if (info == XLOG_HEAP_LOCK)
155 : {
156 16 : xl_heap_lock *xlrec = (xl_heap_lock *) rec;
157 :
158 16 : appendStringInfo(buf, "xmax: %u, off: %u, ",
159 16 : xlrec->xmax, xlrec->offnum);
160 16 : infobits_desc(buf, xlrec->infobits_set, "infobits");
161 16 : appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
162 : }
163 0 : else if (info == XLOG_HEAP_INPLACE)
164 : {
165 0 : xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
166 :
167 0 : appendStringInfo(buf, "off: %u", xlrec->offnum);
168 : }
169 61870 : }
170 :
171 : void
172 122 : heap2_desc(StringInfo buf, XLogReaderState *record)
173 : {
174 122 : char *rec = XLogRecGetData(record);
175 122 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
176 :
177 122 : info &= XLOG_HEAP_OPMASK;
178 122 : if (info == XLOG_HEAP2_PRUNE)
179 : {
180 90 : xl_heap_prune *xlrec = (xl_heap_prune *) rec;
181 :
182 90 : appendStringInfo(buf, "snapshotConflictHorizon: %u, nredirected: %u, ndead: %u",
183 : xlrec->snapshotConflictHorizon,
184 90 : xlrec->nredirected,
185 90 : xlrec->ndead);
186 :
187 90 : if (XLogRecHasBlockData(record, 0))
188 : {
189 : OffsetNumber *end;
190 : OffsetNumber *redirected;
191 : OffsetNumber *nowdead;
192 : OffsetNumber *nowunused;
193 : int nredirected;
194 : int nunused;
195 : Size datalen;
196 :
197 90 : redirected = (OffsetNumber *) XLogRecGetBlockData(record, 0,
198 : &datalen);
199 :
200 90 : nredirected = xlrec->nredirected;
201 90 : end = (OffsetNumber *) ((char *) redirected + datalen);
202 90 : nowdead = redirected + (nredirected * 2);
203 90 : nowunused = nowdead + xlrec->ndead;
204 90 : nunused = (end - nowunused);
205 : Assert(nunused >= 0);
206 :
207 90 : appendStringInfo(buf, ", nunused: %d", nunused);
208 :
209 90 : appendStringInfoString(buf, ", redirected:");
210 90 : array_desc(buf, redirected, sizeof(OffsetNumber) * 2,
211 : nredirected, &redirect_elem_desc, NULL);
212 90 : appendStringInfoString(buf, ", dead:");
213 90 : array_desc(buf, nowdead, sizeof(OffsetNumber), xlrec->ndead,
214 : &offset_elem_desc, NULL);
215 90 : appendStringInfoString(buf, ", unused:");
216 90 : array_desc(buf, nowunused, sizeof(OffsetNumber), nunused,
217 : &offset_elem_desc, NULL);
218 : }
219 : }
220 32 : else if (info == XLOG_HEAP2_VACUUM)
221 : {
222 0 : xl_heap_vacuum *xlrec = (xl_heap_vacuum *) rec;
223 :
224 0 : appendStringInfo(buf, "nunused: %u", xlrec->nunused);
225 :
226 0 : if (XLogRecHasBlockData(record, 0))
227 : {
228 : OffsetNumber *nowunused;
229 :
230 0 : nowunused = (OffsetNumber *) XLogRecGetBlockData(record, 0, NULL);
231 :
232 0 : appendStringInfoString(buf, ", unused:");
233 0 : array_desc(buf, nowunused, sizeof(OffsetNumber), xlrec->nunused,
234 : &offset_elem_desc, NULL);
235 : }
236 : }
237 32 : else if (info == XLOG_HEAP2_FREEZE_PAGE)
238 : {
239 0 : xl_heap_freeze_page *xlrec = (xl_heap_freeze_page *) rec;
240 :
241 0 : appendStringInfo(buf, "snapshotConflictHorizon: %u, nplans: %u",
242 0 : xlrec->snapshotConflictHorizon, xlrec->nplans);
243 :
244 0 : if (XLogRecHasBlockData(record, 0))
245 : {
246 : xl_heap_freeze_plan *plans;
247 : OffsetNumber *offsets;
248 :
249 0 : plans = (xl_heap_freeze_plan *) XLogRecGetBlockData(record, 0, NULL);
250 0 : offsets = (OffsetNumber *) ((char *) plans +
251 0 : (xlrec->nplans *
252 : sizeof(xl_heap_freeze_plan)));
253 0 : appendStringInfoString(buf, ", plans:");
254 0 : array_desc(buf, plans, sizeof(xl_heap_freeze_plan), xlrec->nplans,
255 : &plan_elem_desc, &offsets);
256 : }
257 : }
258 32 : else if (info == XLOG_HEAP2_VISIBLE)
259 : {
260 0 : xl_heap_visible *xlrec = (xl_heap_visible *) rec;
261 :
262 0 : appendStringInfo(buf, "snapshotConflictHorizon: %u, flags: 0x%02X",
263 0 : xlrec->snapshotConflictHorizon, xlrec->flags);
264 : }
265 32 : else if (info == XLOG_HEAP2_MULTI_INSERT)
266 : {
267 32 : xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
268 32 : bool isinit = (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE) != 0;
269 :
270 32 : appendStringInfo(buf, "ntuples: %d, flags: 0x%02X", xlrec->ntuples,
271 32 : xlrec->flags);
272 :
273 32 : if (XLogRecHasBlockData(record, 0) && !isinit)
274 : {
275 26 : appendStringInfoString(buf, ", offsets:");
276 26 : array_desc(buf, xlrec->offsets, sizeof(OffsetNumber),
277 26 : xlrec->ntuples, &offset_elem_desc, NULL);
278 : }
279 : }
280 0 : else if (info == XLOG_HEAP2_LOCK_UPDATED)
281 : {
282 0 : xl_heap_lock_updated *xlrec = (xl_heap_lock_updated *) rec;
283 :
284 0 : appendStringInfo(buf, "xmax: %u, off: %u, ",
285 0 : xlrec->xmax, xlrec->offnum);
286 0 : infobits_desc(buf, xlrec->infobits_set, "infobits");
287 0 : appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
288 : }
289 0 : else if (info == XLOG_HEAP2_NEW_CID)
290 : {
291 0 : xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec;
292 :
293 0 : 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 0 : ItemPointerGetBlockNumber(&(xlrec->target_tid)),
298 0 : ItemPointerGetOffsetNumber(&(xlrec->target_tid)));
299 0 : appendStringInfo(buf, ", cmin: %u, cmax: %u, combo: %u",
300 : xlrec->cmin, xlrec->cmax, xlrec->combocid);
301 : }
302 122 : }
303 :
304 : const char *
305 61870 : heap_identify(uint8 info)
306 : {
307 61870 : const char *id = NULL;
308 :
309 61870 : switch (info & ~XLR_INFO_MASK)
310 : {
311 58970 : case XLOG_HEAP_INSERT:
312 58970 : id = "INSERT";
313 58970 : break;
314 2822 : case XLOG_HEAP_INSERT | XLOG_HEAP_INIT_PAGE:
315 2822 : id = "INSERT+INIT";
316 2822 : break;
317 16 : case XLOG_HEAP_DELETE:
318 16 : id = "DELETE";
319 16 : break;
320 14 : case XLOG_HEAP_UPDATE:
321 14 : id = "UPDATE";
322 14 : break;
323 2 : case XLOG_HEAP_UPDATE | XLOG_HEAP_INIT_PAGE:
324 2 : id = "UPDATE+INIT";
325 2 : break;
326 30 : case XLOG_HEAP_HOT_UPDATE:
327 30 : id = "HOT_UPDATE";
328 30 : break;
329 0 : case XLOG_HEAP_HOT_UPDATE | XLOG_HEAP_INIT_PAGE:
330 0 : id = "HOT_UPDATE+INIT";
331 0 : break;
332 0 : case XLOG_HEAP_TRUNCATE:
333 0 : id = "TRUNCATE";
334 0 : break;
335 0 : case XLOG_HEAP_CONFIRM:
336 0 : id = "HEAP_CONFIRM";
337 0 : break;
338 16 : case XLOG_HEAP_LOCK:
339 16 : id = "LOCK";
340 16 : break;
341 0 : case XLOG_HEAP_INPLACE:
342 0 : id = "INPLACE";
343 0 : break;
344 : }
345 :
346 61870 : return id;
347 : }
348 :
349 : const char *
350 122 : heap2_identify(uint8 info)
351 : {
352 122 : const char *id = NULL;
353 :
354 122 : switch (info & ~XLR_INFO_MASK)
355 : {
356 90 : case XLOG_HEAP2_PRUNE:
357 90 : id = "PRUNE";
358 90 : break;
359 0 : case XLOG_HEAP2_VACUUM:
360 0 : id = "VACUUM";
361 0 : break;
362 0 : case XLOG_HEAP2_FREEZE_PAGE:
363 0 : id = "FREEZE_PAGE";
364 0 : break;
365 0 : case XLOG_HEAP2_VISIBLE:
366 0 : id = "VISIBLE";
367 0 : break;
368 32 : case XLOG_HEAP2_MULTI_INSERT:
369 32 : id = "MULTI_INSERT";
370 32 : break;
371 0 : case XLOG_HEAP2_MULTI_INSERT | XLOG_HEAP_INIT_PAGE:
372 0 : id = "MULTI_INSERT+INIT";
373 0 : break;
374 0 : case XLOG_HEAP2_LOCK_UPDATED:
375 0 : id = "LOCK_UPDATED";
376 0 : break;
377 0 : case XLOG_HEAP2_NEW_CID:
378 0 : id = "NEW_CID";
379 0 : break;
380 0 : case XLOG_HEAP2_REWRITE:
381 0 : id = "REWRITE";
382 0 : break;
383 : }
384 :
385 122 : return id;
386 : }
|