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 96 : infobits_desc(StringInfo buf, uint8 infobits, const char *keyname)
26 : {
27 96 : appendStringInfo(buf, "%s: [", keyname);
28 :
29 : Assert(buf->data[buf->len - 1] != ' ');
30 :
31 96 : if (infobits & XLHL_XMAX_IS_MULTI)
32 0 : appendStringInfoString(buf, "IS_MULTI, ");
33 96 : if (infobits & XLHL_XMAX_LOCK_ONLY)
34 12 : appendStringInfoString(buf, "LOCK_ONLY, ");
35 96 : if (infobits & XLHL_XMAX_EXCL_LOCK)
36 12 : appendStringInfoString(buf, "EXCL_LOCK, ");
37 96 : if (infobits & XLHL_XMAX_KEYSHR_LOCK)
38 0 : appendStringInfoString(buf, "KEYSHR_LOCK, ");
39 96 : if (infobits & XLHL_KEYS_UPDATED)
40 40 : appendStringInfoString(buf, "KEYS_UPDATED, ");
41 :
42 96 : if (buf->data[buf->len - 1] == ' ')
43 : {
44 : /* Truncate-away final unneeded ", " */
45 : Assert(buf->data[buf->len - 2] == ',');
46 52 : buf->len -= 2;
47 52 : buf->data[buf->len] = '\0';
48 : }
49 :
50 96 : appendStringInfoChar(buf, ']');
51 96 : }
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 : appendStringInfoChar(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 : appendStringInfoString(buf, " }");
92 0 : }
93 :
94 : void
95 61898 : heap_desc(StringInfo buf, XLogReaderState *record)
96 : {
97 61898 : char *rec = XLogRecGetData(record);
98 61898 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
99 :
100 61898 : info &= XLOG_HEAP_OPMASK;
101 61898 : if (info == XLOG_HEAP_INSERT)
102 : {
103 61798 : xl_heap_insert *xlrec = (xl_heap_insert *) rec;
104 :
105 61798 : appendStringInfo(buf, "off: %u, flags: 0x%02X",
106 61798 : xlrec->offnum,
107 61798 : xlrec->flags);
108 : }
109 100 : else if (info == XLOG_HEAP_DELETE)
110 : {
111 40 : xl_heap_delete *xlrec = (xl_heap_delete *) rec;
112 :
113 40 : appendStringInfo(buf, "xmax: %u, off: %u, ",
114 40 : xlrec->xmax, xlrec->offnum);
115 40 : infobits_desc(buf, xlrec->infobits_set, "infobits");
116 40 : appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
117 : }
118 60 : else if (info == XLOG_HEAP_UPDATE)
119 : {
120 12 : xl_heap_update *xlrec = (xl_heap_update *) rec;
121 :
122 12 : appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
123 12 : xlrec->old_xmax, xlrec->old_offnum);
124 12 : infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
125 12 : appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
126 12 : xlrec->flags, xlrec->new_xmax, xlrec->new_offnum);
127 : }
128 48 : else if (info == XLOG_HEAP_HOT_UPDATE)
129 : {
130 32 : xl_heap_update *xlrec = (xl_heap_update *) rec;
131 :
132 32 : appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
133 32 : xlrec->old_xmax, xlrec->old_offnum);
134 32 : infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
135 32 : appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
136 32 : 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 12 : xl_heap_lock *xlrec = (xl_heap_lock *) rec;
157 :
158 12 : appendStringInfo(buf, "xmax: %u, off: %u, ",
159 12 : xlrec->xmax, xlrec->offnum);
160 12 : infobits_desc(buf, xlrec->infobits_set, "infobits");
161 12 : appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
162 : }
163 4 : else if (info == XLOG_HEAP_INPLACE)
164 : {
165 4 : xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
166 :
167 4 : appendStringInfo(buf, "off: %u", xlrec->offnum);
168 : }
169 61898 : }
170 :
171 : void
172 128 : heap2_desc(StringInfo buf, XLogReaderState *record)
173 : {
174 128 : char *rec = XLogRecGetData(record);
175 128 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
176 :
177 128 : info &= XLOG_HEAP_OPMASK;
178 128 : if (info == XLOG_HEAP2_PRUNE)
179 : {
180 80 : xl_heap_prune *xlrec = (xl_heap_prune *) rec;
181 :
182 80 : appendStringInfo(buf, "snapshotConflictHorizon: %u, nredirected: %u, ndead: %u",
183 : xlrec->snapshotConflictHorizon,
184 80 : xlrec->nredirected,
185 80 : xlrec->ndead);
186 :
187 80 : 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 80 : redirected = (OffsetNumber *) XLogRecGetBlockData(record, 0,
198 : &datalen);
199 :
200 80 : nredirected = xlrec->nredirected;
201 80 : end = (OffsetNumber *) ((char *) redirected + datalen);
202 80 : nowdead = redirected + (nredirected * 2);
203 80 : nowunused = nowdead + xlrec->ndead;
204 80 : nunused = (end - nowunused);
205 : Assert(nunused >= 0);
206 :
207 80 : appendStringInfo(buf, ", nunused: %d", nunused);
208 :
209 80 : appendStringInfoString(buf, ", redirected:");
210 80 : array_desc(buf, redirected, sizeof(OffsetNumber) * 2,
211 : nredirected, &redirect_elem_desc, NULL);
212 80 : appendStringInfoString(buf, ", dead:");
213 80 : array_desc(buf, nowdead, sizeof(OffsetNumber), xlrec->ndead,
214 : &offset_elem_desc, NULL);
215 80 : appendStringInfoString(buf, ", unused:");
216 80 : array_desc(buf, nowunused, sizeof(OffsetNumber), nunused,
217 : &offset_elem_desc, NULL);
218 : }
219 : }
220 48 : else if (info == XLOG_HEAP2_VACUUM)
221 : {
222 4 : xl_heap_vacuum *xlrec = (xl_heap_vacuum *) rec;
223 :
224 4 : appendStringInfo(buf, "nunused: %u", xlrec->nunused);
225 :
226 4 : if (XLogRecHasBlockData(record, 0))
227 : {
228 : OffsetNumber *nowunused;
229 :
230 4 : nowunused = (OffsetNumber *) XLogRecGetBlockData(record, 0, NULL);
231 :
232 4 : appendStringInfoString(buf, ", unused:");
233 4 : array_desc(buf, nowunused, sizeof(OffsetNumber), xlrec->nunused,
234 : &offset_elem_desc, NULL);
235 : }
236 : }
237 44 : 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 44 : else if (info == XLOG_HEAP2_VISIBLE)
259 : {
260 4 : xl_heap_visible *xlrec = (xl_heap_visible *) rec;
261 :
262 4 : appendStringInfo(buf, "snapshotConflictHorizon: %u, flags: 0x%02X",
263 4 : xlrec->snapshotConflictHorizon, xlrec->flags);
264 : }
265 40 : else if (info == XLOG_HEAP2_MULTI_INSERT)
266 : {
267 40 : xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
268 40 : bool isinit = (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE) != 0;
269 :
270 40 : appendStringInfo(buf, "ntuples: %d, flags: 0x%02X", xlrec->ntuples,
271 40 : xlrec->flags);
272 :
273 40 : if (XLogRecHasBlockData(record, 0) && !isinit)
274 : {
275 34 : appendStringInfoString(buf, ", offsets:");
276 34 : array_desc(buf, xlrec->offsets, sizeof(OffsetNumber),
277 34 : 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 128 : }
303 :
304 : const char *
305 61898 : heap_identify(uint8 info)
306 : {
307 61898 : const char *id = NULL;
308 :
309 61898 : switch (info & ~XLR_INFO_MASK)
310 : {
311 58976 : case XLOG_HEAP_INSERT:
312 58976 : id = "INSERT";
313 58976 : break;
314 2822 : case XLOG_HEAP_INSERT | XLOG_HEAP_INIT_PAGE:
315 2822 : id = "INSERT+INIT";
316 2822 : break;
317 40 : case XLOG_HEAP_DELETE:
318 40 : id = "DELETE";
319 40 : break;
320 10 : case XLOG_HEAP_UPDATE:
321 10 : id = "UPDATE";
322 10 : break;
323 2 : case XLOG_HEAP_UPDATE | XLOG_HEAP_INIT_PAGE:
324 2 : id = "UPDATE+INIT";
325 2 : break;
326 32 : case XLOG_HEAP_HOT_UPDATE:
327 32 : id = "HOT_UPDATE";
328 32 : 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 12 : case XLOG_HEAP_LOCK:
339 12 : id = "LOCK";
340 12 : break;
341 4 : case XLOG_HEAP_INPLACE:
342 4 : id = "INPLACE";
343 4 : break;
344 : }
345 :
346 61898 : return id;
347 : }
348 :
349 : const char *
350 128 : heap2_identify(uint8 info)
351 : {
352 128 : const char *id = NULL;
353 :
354 128 : switch (info & ~XLR_INFO_MASK)
355 : {
356 80 : case XLOG_HEAP2_PRUNE:
357 80 : id = "PRUNE";
358 80 : break;
359 4 : case XLOG_HEAP2_VACUUM:
360 4 : id = "VACUUM";
361 4 : break;
362 0 : case XLOG_HEAP2_FREEZE_PAGE:
363 0 : id = "FREEZE_PAGE";
364 0 : break;
365 4 : case XLOG_HEAP2_VISIBLE:
366 4 : id = "VISIBLE";
367 4 : break;
368 40 : case XLOG_HEAP2_MULTI_INSERT:
369 40 : id = "MULTI_INSERT";
370 40 : 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 128 : return id;
386 : }
|