PostgreSQL Source Code  git master
xactdesc.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * xactdesc.c
4  * rmgr descriptor routines for access/transam/xact.c
5  *
6  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/access/rmgrdesc/xactdesc.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/transam.h"
18 #include "access/xact.h"
19 #include "storage/sinval.h"
20 #include "storage/standbydefs.h"
21 #include "utils/timestamp.h"
22 
23 /*
24  * Parse the WAL format of an xact commit and abort records into an easier to
25  * understand format.
26  *
27  * This routines are in xactdesc.c because they're accessed in backend (when
28  * replaying WAL) and frontend (pg_waldump) code. This file is the only xact
29  * specific one shared between both. They're complicated enough that
30  * duplication would be bothersome.
31  */
32 
33 void
35 {
36  char *data = ((char *) xlrec) + MinSizeOfXactCommit;
37 
38  memset(parsed, 0, sizeof(*parsed));
39 
40  parsed->xinfo = 0; /* default, if no XLOG_XACT_HAS_INFO is
41  * present */
42 
43  parsed->xact_time = xlrec->xact_time;
44 
45  if (info & XLOG_XACT_HAS_INFO)
46  {
47  xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data;
48 
49  parsed->xinfo = xl_xinfo->xinfo;
50 
51  data += sizeof(xl_xact_xinfo);
52  }
53 
54  if (parsed->xinfo & XACT_XINFO_HAS_DBINFO)
55  {
56  xl_xact_dbinfo *xl_dbinfo = (xl_xact_dbinfo *) data;
57 
58  parsed->dbId = xl_dbinfo->dbId;
59  parsed->tsId = xl_dbinfo->tsId;
60 
61  data += sizeof(xl_xact_dbinfo);
62  }
63 
64  if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS)
65  {
66  xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data;
67 
68  parsed->nsubxacts = xl_subxacts->nsubxacts;
69  parsed->subxacts = xl_subxacts->subxacts;
70 
71  data += MinSizeOfXactSubxacts;
72  data += parsed->nsubxacts * sizeof(TransactionId);
73  }
74 
75  if (parsed->xinfo & XACT_XINFO_HAS_RELFILENODES)
76  {
77  xl_xact_relfilenodes *xl_relfilenodes = (xl_xact_relfilenodes *) data;
78 
79  parsed->nrels = xl_relfilenodes->nrels;
80  parsed->xnodes = xl_relfilenodes->xnodes;
81 
83  data += xl_relfilenodes->nrels * sizeof(RelFileNode);
84  }
85 
86  if (parsed->xinfo & XACT_XINFO_HAS_INVALS)
87  {
88  xl_xact_invals *xl_invals = (xl_xact_invals *) data;
89 
90  parsed->nmsgs = xl_invals->nmsgs;
91  parsed->msgs = xl_invals->msgs;
92 
93  data += MinSizeOfXactInvals;
94  data += xl_invals->nmsgs * sizeof(SharedInvalidationMessage);
95  }
96 
97  if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE)
98  {
99  xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data;
100 
101  parsed->twophase_xid = xl_twophase->xid;
102 
103  data += sizeof(xl_xact_twophase);
104 
105  if (parsed->xinfo & XACT_XINFO_HAS_GID)
106  {
107  strlcpy(parsed->twophase_gid, data, sizeof(parsed->twophase_gid));
108  data += strlen(data) + 1;
109  }
110  }
111 
112  /* Note: no alignment is guaranteed after this point */
113 
114  if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
115  {
116  xl_xact_origin xl_origin;
117 
118  /* no alignment is guaranteed, so copy onto stack */
119  memcpy(&xl_origin, data, sizeof(xl_origin));
120 
121  parsed->origin_lsn = xl_origin.origin_lsn;
122  parsed->origin_timestamp = xl_origin.origin_timestamp;
123 
124  data += sizeof(xl_xact_origin);
125  }
126 }
127 
128 void
130 {
131  char *data = ((char *) xlrec) + MinSizeOfXactAbort;
132 
133  memset(parsed, 0, sizeof(*parsed));
134 
135  parsed->xinfo = 0; /* default, if no XLOG_XACT_HAS_INFO is
136  * present */
137 
138  parsed->xact_time = xlrec->xact_time;
139 
140  if (info & XLOG_XACT_HAS_INFO)
141  {
142  xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data;
143 
144  parsed->xinfo = xl_xinfo->xinfo;
145 
146  data += sizeof(xl_xact_xinfo);
147  }
148 
149  if (parsed->xinfo & XACT_XINFO_HAS_DBINFO)
150  {
151  xl_xact_dbinfo *xl_dbinfo = (xl_xact_dbinfo *) data;
152 
153  parsed->dbId = xl_dbinfo->dbId;
154  parsed->tsId = xl_dbinfo->tsId;
155 
156  data += sizeof(xl_xact_dbinfo);
157  }
158 
159  if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS)
160  {
161  xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data;
162 
163  parsed->nsubxacts = xl_subxacts->nsubxacts;
164  parsed->subxacts = xl_subxacts->subxacts;
165 
166  data += MinSizeOfXactSubxacts;
167  data += parsed->nsubxacts * sizeof(TransactionId);
168  }
169 
170  if (parsed->xinfo & XACT_XINFO_HAS_RELFILENODES)
171  {
172  xl_xact_relfilenodes *xl_relfilenodes = (xl_xact_relfilenodes *) data;
173 
174  parsed->nrels = xl_relfilenodes->nrels;
175  parsed->xnodes = xl_relfilenodes->xnodes;
176 
178  data += xl_relfilenodes->nrels * sizeof(RelFileNode);
179  }
180 
181  if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE)
182  {
183  xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data;
184 
185  parsed->twophase_xid = xl_twophase->xid;
186 
187  data += sizeof(xl_xact_twophase);
188 
189  if (parsed->xinfo & XACT_XINFO_HAS_GID)
190  {
191  strlcpy(parsed->twophase_gid, data, sizeof(parsed->twophase_gid));
192  data += strlen(data) + 1;
193  }
194  }
195 
196  /* Note: no alignment is guaranteed after this point */
197 
198  if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
199  {
200  xl_xact_origin xl_origin;
201 
202  /* no alignment is guaranteed, so copy onto stack */
203  memcpy(&xl_origin, data, sizeof(xl_origin));
204 
205  parsed->origin_lsn = xl_origin.origin_lsn;
206  parsed->origin_timestamp = xl_origin.origin_timestamp;
207 
208  data += sizeof(xl_xact_origin);
209  }
210 }
211 
212 /*
213  * ParsePrepareRecord
214  */
215 void
217 {
218  char *bufptr;
219 
220  bufptr = ((char *) xlrec) + MAXALIGN(sizeof(xl_xact_prepare));
221 
222  memset(parsed, 0, sizeof(*parsed));
223 
224  parsed->xact_time = xlrec->prepared_at;
225  parsed->origin_lsn = xlrec->origin_lsn;
226  parsed->origin_timestamp = xlrec->origin_timestamp;
227  parsed->twophase_xid = xlrec->xid;
228  parsed->dbId = xlrec->database;
229  parsed->nsubxacts = xlrec->nsubxacts;
230  parsed->nrels = xlrec->ncommitrels;
231  parsed->nabortrels = xlrec->nabortrels;
232  parsed->nmsgs = xlrec->ninvalmsgs;
233 
234  strncpy(parsed->twophase_gid, bufptr, xlrec->gidlen);
235  bufptr += MAXALIGN(xlrec->gidlen);
236 
237  parsed->subxacts = (TransactionId *) bufptr;
238  bufptr += MAXALIGN(xlrec->nsubxacts * sizeof(TransactionId));
239 
240  parsed->xnodes = (RelFileNode *) bufptr;
241  bufptr += MAXALIGN(xlrec->ncommitrels * sizeof(RelFileNode));
242 
243  parsed->abortnodes = (RelFileNode *) bufptr;
244  bufptr += MAXALIGN(xlrec->nabortrels * sizeof(RelFileNode));
245 
246  parsed->msgs = (SharedInvalidationMessage *) bufptr;
247  bufptr += MAXALIGN(xlrec->ninvalmsgs * sizeof(SharedInvalidationMessage));
248 }
249 
250 static void
252  RelFileNode *xnodes)
253 {
254  int i;
255 
256  if (nrels > 0)
257  {
258  appendStringInfo(buf, "; %s:", label);
259  for (i = 0; i < nrels; i++)
260  {
261  char *path = relpathperm(xnodes[i], MAIN_FORKNUM);
262 
263  appendStringInfo(buf, " %s", path);
264  pfree(path);
265  }
266  }
267 }
268 
269 static void
270 xact_desc_subxacts(StringInfo buf, int nsubxacts, TransactionId *subxacts)
271 {
272  int i;
273 
274  if (nsubxacts > 0)
275  {
276  appendStringInfoString(buf, "; subxacts:");
277  for (i = 0; i < nsubxacts; i++)
278  appendStringInfo(buf, " %u", subxacts[i]);
279  }
280 }
281 
282 static void
284 {
285  xl_xact_parsed_commit parsed;
286 
287  ParseCommitRecord(info, xlrec, &parsed);
288 
289  /* If this is a prepared xact, show the xid of the original xact */
291  appendStringInfo(buf, "%u: ", parsed.twophase_xid);
292 
294 
295  xact_desc_relations(buf, "rels", parsed.nrels, parsed.xnodes);
296  xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
297 
298  standby_desc_invalidations(buf, parsed.nmsgs, parsed.msgs, parsed.dbId,
299  parsed.tsId,
301 
303  appendStringInfoString(buf, "; sync");
304 
305  if (parsed.xinfo & XACT_XINFO_HAS_ORIGIN)
306  {
307  appendStringInfo(buf, "; origin: node %u, lsn %X/%X, at %s",
308  origin_id,
309  LSN_FORMAT_ARGS(parsed.origin_lsn),
311  }
312 }
313 
314 static void
316 {
317  xl_xact_parsed_abort parsed;
318 
319  ParseAbortRecord(info, xlrec, &parsed);
320 
321  /* If this is a prepared xact, show the xid of the original xact */
323  appendStringInfo(buf, "%u: ", parsed.twophase_xid);
324 
326 
327  xact_desc_relations(buf, "rels", parsed.nrels, parsed.xnodes);
328  xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
329 }
330 
331 static void
333 {
334  xl_xact_parsed_prepare parsed;
335 
336  ParsePrepareRecord(info, xlrec, &parsed);
337 
338  appendStringInfo(buf, "gid %s: ", parsed.twophase_gid);
340 
341  xact_desc_relations(buf, "rels(commit)", parsed.nrels, parsed.xnodes);
342  xact_desc_relations(buf, "rels(abort)", parsed.nabortrels,
343  parsed.abortnodes);
344  xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
345 
346  standby_desc_invalidations(buf, parsed.nmsgs, parsed.msgs, parsed.dbId,
347  parsed.tsId, xlrec->initfileinval);
348 }
349 
350 static void
352 {
353  int i;
354 
355  appendStringInfoString(buf, "subxacts:");
356 
357  for (i = 0; i < xlrec->nsubxacts; i++)
358  appendStringInfo(buf, " %u", xlrec->xsub[i]);
359 }
360 
361 void
363 {
364  char *rec = XLogRecGetData(record);
365  uint8 info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
366 
367  if (info == XLOG_XACT_COMMIT || info == XLOG_XACT_COMMIT_PREPARED)
368  {
369  xl_xact_commit *xlrec = (xl_xact_commit *) rec;
370 
371  xact_desc_commit(buf, XLogRecGetInfo(record), xlrec,
372  XLogRecGetOrigin(record));
373  }
374  else if (info == XLOG_XACT_ABORT || info == XLOG_XACT_ABORT_PREPARED)
375  {
376  xl_xact_abort *xlrec = (xl_xact_abort *) rec;
377 
378  xact_desc_abort(buf, XLogRecGetInfo(record), xlrec);
379  }
380  else if (info == XLOG_XACT_PREPARE)
381  {
382  xl_xact_prepare *xlrec = (xl_xact_prepare *) rec;
383 
384  xact_desc_prepare(buf, XLogRecGetInfo(record), xlrec);
385  }
386  else if (info == XLOG_XACT_ASSIGNMENT)
387  {
388  xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
389 
390  /*
391  * Note that we ignore the WAL record's xid, since we're more
392  * interested in the top-level xid that issued the record and which
393  * xids are being reported here.
394  */
395  appendStringInfo(buf, "xtop %u: ", xlrec->xtop);
396  xact_desc_assignment(buf, xlrec);
397  }
398  else if (info == XLOG_XACT_INVALIDATIONS)
399  {
400  xl_xact_invals *xlrec = (xl_xact_invals *) rec;
401 
402  standby_desc_invalidations(buf, xlrec->nmsgs, xlrec->msgs, InvalidOid,
403  InvalidOid, false);
404  }
405 }
406 
407 const char *
409 {
410  const char *id = NULL;
411 
412  switch (info & XLOG_XACT_OPMASK)
413  {
414  case XLOG_XACT_COMMIT:
415  id = "COMMIT";
416  break;
417  case XLOG_XACT_PREPARE:
418  id = "PREPARE";
419  break;
420  case XLOG_XACT_ABORT:
421  id = "ABORT";
422  break;
424  id = "COMMIT_PREPARED";
425  break;
427  id = "ABORT_PREPARED";
428  break;
430  id = "ASSIGNMENT";
431  break;
433  id = "INVALIDATION";
434  break;
435  }
436 
437  return id;
438 }
RelFileNode * xnodes
Definition: xact.h:335
int32 ninvalmsgs
Definition: xact.h:311
#define relpathperm(rnode, forknum)
Definition: relpath.h:83
#define XLOG_XACT_COMMIT
Definition: xact.h:148
int32 nsubxacts
Definition: xact.h:308
#define XACT_XINFO_HAS_ORIGIN
Definition: xact.h:172
#define XactCompletionRelcacheInitFileInval(xinfo)
Definition: xact.h:191
struct xl_xact_xinfo xl_xact_xinfo
#define XLOG_XACT_PREPARE
Definition: xact.h:149
const char * xact_identify(uint8 info)
Definition: xactdesc.c:408
uint32 TransactionId
Definition: c.h:587
int32 ncommitrels
Definition: xact.h:309
void standby_desc_invalidations(StringInfo buf, int nmsgs, SharedInvalidationMessage *msgs, Oid dbId, Oid tsId, bool relcacheInitFileInval)
Definition: standbydesc.c:98
TimestampTz origin_timestamp
Definition: xact.h:346
#define XLOG_XACT_INVALIDATIONS
Definition: xact.h:154
TransactionId xid
Definition: xact.h:261
TransactionId twophase_xid
Definition: xact.h:340
unsigned char uint8
Definition: c.h:439
TransactionId * subxacts
Definition: xact.h:332
uint16 RepOriginId
Definition: xlogdefs.h:65
#define MinSizeOfXactAbort
Definition: xact.h:298
#define XLOG_XACT_HAS_INFO
Definition: xact.h:161
SharedInvalidationMessage * msgs
Definition: xact.h:338
TransactionId xtop
Definition: xact.h:198
XLogRecPtr origin_lsn
Definition: xact.h:345
uint16 gidlen
Definition: xact.h:313
TransactionId xsub[FLEXIBLE_ARRAY_MEMBER]
Definition: xact.h:200
#define XACT_XINFO_HAS_SUBXACTS
Definition: xact.h:168
struct xl_xact_dbinfo xl_xact_dbinfo
#define MinSizeOfXactRelfilenodes
Definition: xact.h:250
TimestampTz xact_time
Definition: xact.h:287
Oid tsId
Definition: xact.h:235
#define XLogRecGetOrigin(decoder)
Definition: xlogreader.h:318
Oid database
Definition: xact.h:305
struct xl_xact_origin xl_xact_origin
static void xact_desc_relations(StringInfo buf, char *label, int nrels, RelFileNode *xnodes)
Definition: xactdesc.c:251
RelFileNode xnodes[FLEXIBLE_ARRAY_MEMBER]
Definition: xact.h:248
int32 nabortrels
Definition: xact.h:310
#define MinSizeOfXactSubxacts
Definition: xact.h:243
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:43
void pfree(void *pointer)
Definition: mcxt.c:1169
#define XLogRecGetData(decoder)
Definition: xlogreader.h:320
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
#define MinSizeOfXactCommit
Definition: xact.h:283
SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER]
Definition: xact.h:255
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
struct RelFileNode RelFileNode
void ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed)
Definition: xactdesc.c:34
static char * buf
Definition: pg_test_fsync.c:68
TimestampTz xact_time
Definition: xact.h:272
#define XLOG_XACT_ABORT_PREPARED
Definition: xact.h:152
XLogRecPtr origin_lsn
Definition: xact.h:314
static void xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
Definition: xactdesc.c:315
struct xl_xact_twophase xl_xact_twophase
#define MinSizeOfXactInvals
Definition: xact.h:257
#define XACT_XINFO_HAS_DBINFO
Definition: xact.h:167
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:315
XLogRecPtr origin_lsn
Definition: xact.h:266
TransactionId * subxacts
Definition: xact.h:360
#define XLOG_XACT_ASSIGNMENT
Definition: xact.h:153
uint32 xinfo
Definition: xact.h:229
XLogRecPtr origin_lsn
Definition: xact.h:368
static char * label
RelFileNode * xnodes
Definition: xact.h:363
int nsubxacts
Definition: xact.h:240
#define XACT_XINFO_HAS_TWOPHASE
Definition: xact.h:171
#define InvalidOid
Definition: postgres_ext.h:36
void ParsePrepareRecord(uint8 info, xl_xact_prepare *xlrec, xl_xact_parsed_prepare *parsed)
Definition: xactdesc.c:216
Oid dbId
Definition: xact.h:234
TransactionId twophase_xid
Definition: xact.h:365
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define XactCompletionForceSyncCommit(xinfo)
Definition: xact.h:193
bool initfileinval
Definition: xact.h:312
RelFileNode * abortnodes
Definition: xact.h:343
#define XLOG_XACT_ABORT
Definition: xact.h:150
static void xact_desc_prepare(StringInfo buf, uint8 info, xl_xact_prepare *xlrec)
Definition: xactdesc.c:332
TimestampTz origin_timestamp
Definition: xact.h:315
#define XLOG_XACT_OPMASK
Definition: xact.h:158
TimestampTz xact_time
Definition: xact.h:353
#define MAXALIGN(LEN)
Definition: c.h:757
void ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
Definition: xactdesc.c:129
TransactionId xid
Definition: xact.h:304
TimestampTz origin_timestamp
Definition: xact.h:267
static void xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
Definition: xactdesc.c:351
int i
#define XACT_XINFO_HAS_INVALS
Definition: xact.h:170
#define XACT_XINFO_HAS_RELFILENODES
Definition: xact.h:169
TimestampTz prepared_at
Definition: xact.h:306
void xact_desc(StringInfo buf, XLogReaderState *record)
Definition: xactdesc.c:362
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define XLOG_XACT_COMMIT_PREPARED
Definition: xact.h:151
TimestampTz origin_timestamp
Definition: xact.h:369
int nmsgs
Definition: xact.h:254
#define XACT_XINFO_HAS_GID
Definition: xact.h:174
char twophase_gid[GIDSIZE]
Definition: xact.h:341
char twophase_gid[GIDSIZE]
Definition: xact.h:366
TransactionId subxacts[FLEXIBLE_ARRAY_MEMBER]
Definition: xact.h:241
static void xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId origin_id)
Definition: xactdesc.c:283
TimestampTz xact_time
Definition: xact.h:325
static void xact_desc_subxacts(StringInfo buf, int nsubxacts, TransactionId *subxacts)
Definition: xactdesc.c:270
const char * timestamptz_to_str(TimestampTz t)
Definition: timestamp.c:1774