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-2018, 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 static void
214 {
215  xl_xact_parsed_commit parsed;
216  int i;
217 
218  ParseCommitRecord(info, xlrec, &parsed);
219 
220  /* If this is a prepared xact, show the xid of the original xact */
222  appendStringInfo(buf, "%u: ", parsed.twophase_xid);
223 
225 
226  if (parsed.nrels > 0)
227  {
228  appendStringInfoString(buf, "; rels:");
229  for (i = 0; i < parsed.nrels; i++)
230  {
231  char *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM);
232 
233  appendStringInfo(buf, " %s", path);
234  pfree(path);
235  }
236  }
237  if (parsed.nsubxacts > 0)
238  {
239  appendStringInfoString(buf, "; subxacts:");
240  for (i = 0; i < parsed.nsubxacts; i++)
241  appendStringInfo(buf, " %u", parsed.subxacts[i]);
242  }
243  if (parsed.nmsgs > 0)
244  {
246  buf, parsed.nmsgs, parsed.msgs, parsed.dbId, parsed.tsId,
248  }
249 
251  appendStringInfoString(buf, "; sync");
252 
253  if (parsed.xinfo & XACT_XINFO_HAS_ORIGIN)
254  {
255  appendStringInfo(buf, "; origin: node %u, lsn %X/%X, at %s",
256  origin_id,
257  (uint32) (parsed.origin_lsn >> 32),
258  (uint32) parsed.origin_lsn,
260  }
261 }
262 
263 static void
265 {
266  xl_xact_parsed_abort parsed;
267  int i;
268 
269  ParseAbortRecord(info, xlrec, &parsed);
270 
271  /* If this is a prepared xact, show the xid of the original xact */
273  appendStringInfo(buf, "%u: ", parsed.twophase_xid);
274 
276  if (parsed.nrels > 0)
277  {
278  appendStringInfoString(buf, "; rels:");
279  for (i = 0; i < parsed.nrels; i++)
280  {
281  char *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM);
282 
283  appendStringInfo(buf, " %s", path);
284  pfree(path);
285  }
286  }
287 
288  if (parsed.nsubxacts > 0)
289  {
290  appendStringInfoString(buf, "; subxacts:");
291  for (i = 0; i < parsed.nsubxacts; i++)
292  appendStringInfo(buf, " %u", parsed.subxacts[i]);
293  }
294 }
295 
296 static void
298 {
299  int i;
300 
301  appendStringInfoString(buf, "subxacts:");
302 
303  for (i = 0; i < xlrec->nsubxacts; i++)
304  appendStringInfo(buf, " %u", xlrec->xsub[i]);
305 }
306 
307 void
309 {
310  char *rec = XLogRecGetData(record);
311  uint8 info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
312 
313  if (info == XLOG_XACT_COMMIT || info == XLOG_XACT_COMMIT_PREPARED)
314  {
315  xl_xact_commit *xlrec = (xl_xact_commit *) rec;
316 
317  xact_desc_commit(buf, XLogRecGetInfo(record), xlrec,
318  XLogRecGetOrigin(record));
319  }
320  else if (info == XLOG_XACT_ABORT || info == XLOG_XACT_ABORT_PREPARED)
321  {
322  xl_xact_abort *xlrec = (xl_xact_abort *) rec;
323 
324  xact_desc_abort(buf, XLogRecGetInfo(record), xlrec);
325  }
326  else if (info == XLOG_XACT_ASSIGNMENT)
327  {
328  xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
329 
330  /*
331  * Note that we ignore the WAL record's xid, since we're more
332  * interested in the top-level xid that issued the record and which
333  * xids are being reported here.
334  */
335  appendStringInfo(buf, "xtop %u: ", xlrec->xtop);
336  xact_desc_assignment(buf, xlrec);
337  }
338 }
339 
340 const char *
342 {
343  const char *id = NULL;
344 
345  switch (info & XLOG_XACT_OPMASK)
346  {
347  case XLOG_XACT_COMMIT:
348  id = "COMMIT";
349  break;
350  case XLOG_XACT_PREPARE:
351  id = "PREPARE";
352  break;
353  case XLOG_XACT_ABORT:
354  id = "ABORT";
355  break;
357  id = "COMMIT_PREPARED";
358  break;
360  id = "ABORT_PREPARED";
361  break;
363  id = "ASSIGNMENT";
364  break;
365  }
366 
367  return id;
368 }
RelFileNode * xnodes
Definition: xact.h:309
#define relpathperm(rnode, forknum)
Definition: relpath.h:83
#define XLOG_XACT_COMMIT
Definition: xact.h:140
#define XACT_XINFO_HAS_ORIGIN
Definition: xact.h:164
#define XactCompletionRelcacheInitFileInval(xinfo)
Definition: xact.h:183
struct xl_xact_xinfo xl_xact_xinfo
#define XLOG_XACT_PREPARE
Definition: xact.h:141
const char * xact_identify(uint8 info)
Definition: xactdesc.c:341
uint32 TransactionId
Definition: c.h:474
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:320
TransactionId xid
Definition: xact.h:253
TransactionId twophase_xid
Definition: xact.h:314
unsigned char uint8
Definition: c.h:323
TransactionId * subxacts
Definition: xact.h:306
uint16 RepOriginId
Definition: xlogdefs.h:51
#define MinSizeOfXactAbort
Definition: xact.h:290
#define XLOG_XACT_HAS_INFO
Definition: xact.h:153
SharedInvalidationMessage * msgs
Definition: xact.h:312
TransactionId xtop
Definition: xact.h:190
XLogRecPtr origin_lsn
Definition: xact.h:319
TransactionId xsub[FLEXIBLE_ARRAY_MEMBER]
Definition: xact.h:192
#define XACT_XINFO_HAS_SUBXACTS
Definition: xact.h:160
struct xl_xact_dbinfo xl_xact_dbinfo
#define MinSizeOfXactRelfilenodes
Definition: xact.h:242
TimestampTz xact_time
Definition: xact.h:279
Oid tsId
Definition: xact.h:227
#define XLogRecGetOrigin(decoder)
Definition: xlogreader.h:229
struct xl_xact_origin xl_xact_origin
RelFileNode xnodes[FLEXIBLE_ARRAY_MEMBER]
Definition: xact.h:240
#define MinSizeOfXactSubxacts
Definition: xact.h:235
void pfree(void *pointer)
Definition: mcxt.c:1031
#define XLogRecGetData(decoder)
Definition: xlogreader.h:230
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define MinSizeOfXactCommit
Definition: xact.h:275
SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER]
Definition: xact.h:247
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
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:67
TimestampTz xact_time
Definition: xact.h:264
#define XLOG_XACT_ABORT_PREPARED
Definition: xact.h:144
static void xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
Definition: xactdesc.c:264
struct xl_xact_twophase xl_xact_twophase
unsigned int uint32
Definition: c.h:325
#define MinSizeOfXactInvals
Definition: xact.h:249
#define XACT_XINFO_HAS_DBINFO
Definition: xact.h:159
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:226
XLogRecPtr origin_lsn
Definition: xact.h:258
TransactionId * subxacts
Definition: xact.h:334
#define XLOG_XACT_ASSIGNMENT
Definition: xact.h:145
uint32 xinfo
Definition: xact.h:221
XLogRecPtr origin_lsn
Definition: xact.h:342
RelFileNode * xnodes
Definition: xact.h:337
int nsubxacts
Definition: xact.h:232
#define XACT_XINFO_HAS_TWOPHASE
Definition: xact.h:163
Oid dbId
Definition: xact.h:226
TransactionId twophase_xid
Definition: xact.h:339
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define XactCompletionForceSyncCommit(xinfo)
Definition: xact.h:185
#define XLOG_XACT_ABORT
Definition: xact.h:142
#define XLOG_XACT_OPMASK
Definition: xact.h:150
TimestampTz xact_time
Definition: xact.h:327
void ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
Definition: xactdesc.c:129
TimestampTz origin_timestamp
Definition: xact.h:259
static void xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
Definition: xactdesc.c:297
int i
#define XACT_XINFO_HAS_INVALS
Definition: xact.h:162
#define XACT_XINFO_HAS_RELFILENODES
Definition: xact.h:161
void xact_desc(StringInfo buf, XLogReaderState *record)
Definition: xactdesc.c:308
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define XLOG_XACT_COMMIT_PREPARED
Definition: xact.h:143
TimestampTz origin_timestamp
Definition: xact.h:343
int nmsgs
Definition: xact.h:246
#define XACT_XINFO_HAS_GID
Definition: xact.h:166
char twophase_gid[GIDSIZE]
Definition: xact.h:315
char twophase_gid[GIDSIZE]
Definition: xact.h:340
TransactionId subxacts[FLEXIBLE_ARRAY_MEMBER]
Definition: xact.h:233
static void xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId origin_id)
Definition: xactdesc.c:213
TimestampTz xact_time
Definition: xact.h:299
const char * timestamptz_to_str(TimestampTz t)
Definition: timestamp.c:1710