Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * xactdesc.c
4 : * rmgr descriptor routines for access/transam/xact.c
5 : *
6 : * Portions Copyright (c) 1996-2017, 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 "catalog/catalog.h"
20 : #include "storage/sinval.h"
21 : #include "storage/standbydefs.h"
22 : #include "utils/timestamp.h"
23 :
24 : /*
25 : * Parse the WAL format of an xact commit and abort records into an easier to
26 : * understand format.
27 : *
28 : * This routines are in xactdesc.c because they're accessed in backend (when
29 : * replaying WAL) and frontend (pg_waldump) code. This file is the only xact
30 : * specific one shared between both. They're complicated enough that
31 : * duplication would be bothersome.
32 : */
33 :
34 : void
35 0 : ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed)
36 : {
37 0 : char *data = ((char *) xlrec) + MinSizeOfXactCommit;
38 :
39 0 : memset(parsed, 0, sizeof(*parsed));
40 :
41 0 : parsed->xinfo = 0; /* default, if no XLOG_XACT_HAS_INFO is
42 : * present */
43 :
44 0 : parsed->xact_time = xlrec->xact_time;
45 :
46 0 : if (info & XLOG_XACT_HAS_INFO)
47 : {
48 0 : xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data;
49 :
50 0 : parsed->xinfo = xl_xinfo->xinfo;
51 :
52 0 : data += sizeof(xl_xact_xinfo);
53 : }
54 :
55 0 : if (parsed->xinfo & XACT_XINFO_HAS_DBINFO)
56 : {
57 0 : xl_xact_dbinfo *xl_dbinfo = (xl_xact_dbinfo *) data;
58 :
59 0 : parsed->dbId = xl_dbinfo->dbId;
60 0 : parsed->tsId = xl_dbinfo->tsId;
61 :
62 0 : data += sizeof(xl_xact_dbinfo);
63 : }
64 :
65 0 : if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS)
66 : {
67 0 : xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data;
68 :
69 0 : parsed->nsubxacts = xl_subxacts->nsubxacts;
70 0 : parsed->subxacts = xl_subxacts->subxacts;
71 :
72 0 : data += MinSizeOfXactSubxacts;
73 0 : data += parsed->nsubxacts * sizeof(TransactionId);
74 : }
75 :
76 0 : if (parsed->xinfo & XACT_XINFO_HAS_RELFILENODES)
77 : {
78 0 : xl_xact_relfilenodes *xl_relfilenodes = (xl_xact_relfilenodes *) data;
79 :
80 0 : parsed->nrels = xl_relfilenodes->nrels;
81 0 : parsed->xnodes = xl_relfilenodes->xnodes;
82 :
83 0 : data += MinSizeOfXactRelfilenodes;
84 0 : data += xl_relfilenodes->nrels * sizeof(RelFileNode);
85 : }
86 :
87 0 : if (parsed->xinfo & XACT_XINFO_HAS_INVALS)
88 : {
89 0 : xl_xact_invals *xl_invals = (xl_xact_invals *) data;
90 :
91 0 : parsed->nmsgs = xl_invals->nmsgs;
92 0 : parsed->msgs = xl_invals->msgs;
93 :
94 0 : data += MinSizeOfXactInvals;
95 0 : data += xl_invals->nmsgs * sizeof(SharedInvalidationMessage);
96 : }
97 :
98 0 : if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE)
99 : {
100 0 : xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data;
101 :
102 0 : parsed->twophase_xid = xl_twophase->xid;
103 :
104 0 : data += sizeof(xl_xact_twophase);
105 : }
106 :
107 0 : if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
108 : {
109 : xl_xact_origin xl_origin;
110 :
111 : /* we're only guaranteed 4 byte alignment, so copy onto stack */
112 0 : memcpy(&xl_origin, data, sizeof(xl_origin));
113 :
114 0 : parsed->origin_lsn = xl_origin.origin_lsn;
115 0 : parsed->origin_timestamp = xl_origin.origin_timestamp;
116 :
117 0 : data += sizeof(xl_xact_origin);
118 : }
119 0 : }
120 :
121 : void
122 0 : ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
123 : {
124 0 : char *data = ((char *) xlrec) + MinSizeOfXactAbort;
125 :
126 0 : memset(parsed, 0, sizeof(*parsed));
127 :
128 0 : parsed->xinfo = 0; /* default, if no XLOG_XACT_HAS_INFO is
129 : * present */
130 :
131 0 : parsed->xact_time = xlrec->xact_time;
132 :
133 0 : if (info & XLOG_XACT_HAS_INFO)
134 : {
135 0 : xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data;
136 :
137 0 : parsed->xinfo = xl_xinfo->xinfo;
138 :
139 0 : data += sizeof(xl_xact_xinfo);
140 : }
141 :
142 0 : if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS)
143 : {
144 0 : xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data;
145 :
146 0 : parsed->nsubxacts = xl_subxacts->nsubxacts;
147 0 : parsed->subxacts = xl_subxacts->subxacts;
148 :
149 0 : data += MinSizeOfXactSubxacts;
150 0 : data += parsed->nsubxacts * sizeof(TransactionId);
151 : }
152 :
153 0 : if (parsed->xinfo & XACT_XINFO_HAS_RELFILENODES)
154 : {
155 0 : xl_xact_relfilenodes *xl_relfilenodes = (xl_xact_relfilenodes *) data;
156 :
157 0 : parsed->nrels = xl_relfilenodes->nrels;
158 0 : parsed->xnodes = xl_relfilenodes->xnodes;
159 :
160 0 : data += MinSizeOfXactRelfilenodes;
161 0 : data += xl_relfilenodes->nrels * sizeof(RelFileNode);
162 : }
163 :
164 0 : if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE)
165 : {
166 0 : xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data;
167 :
168 0 : parsed->twophase_xid = xl_twophase->xid;
169 :
170 0 : data += sizeof(xl_xact_twophase);
171 : }
172 0 : }
173 :
174 : static void
175 0 : xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId origin_id)
176 : {
177 : xl_xact_parsed_commit parsed;
178 : int i;
179 :
180 0 : ParseCommitRecord(info, xlrec, &parsed);
181 :
182 : /* If this is a prepared xact, show the xid of the original xact */
183 0 : if (TransactionIdIsValid(parsed.twophase_xid))
184 0 : appendStringInfo(buf, "%u: ", parsed.twophase_xid);
185 :
186 0 : appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
187 :
188 0 : if (parsed.nrels > 0)
189 : {
190 0 : appendStringInfoString(buf, "; rels:");
191 0 : for (i = 0; i < parsed.nrels; i++)
192 : {
193 0 : char *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM);
194 :
195 0 : appendStringInfo(buf, " %s", path);
196 0 : pfree(path);
197 : }
198 : }
199 0 : if (parsed.nsubxacts > 0)
200 : {
201 0 : appendStringInfoString(buf, "; subxacts:");
202 0 : for (i = 0; i < parsed.nsubxacts; i++)
203 0 : appendStringInfo(buf, " %u", parsed.subxacts[i]);
204 : }
205 0 : if (parsed.nmsgs > 0)
206 : {
207 0 : standby_desc_invalidations(
208 : buf, parsed.nmsgs, parsed.msgs, parsed.dbId, parsed.tsId,
209 0 : XactCompletionRelcacheInitFileInval(parsed.xinfo));
210 : }
211 :
212 0 : if (XactCompletionForceSyncCommit(parsed.xinfo))
213 0 : appendStringInfoString(buf, "; sync");
214 :
215 0 : if (parsed.xinfo & XACT_XINFO_HAS_ORIGIN)
216 : {
217 0 : appendStringInfo(buf, "; origin: node %u, lsn %X/%X, at %s",
218 : origin_id,
219 0 : (uint32) (parsed.origin_lsn >> 32),
220 0 : (uint32) parsed.origin_lsn,
221 : timestamptz_to_str(parsed.origin_timestamp));
222 : }
223 0 : }
224 :
225 : static void
226 0 : xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
227 : {
228 : xl_xact_parsed_abort parsed;
229 : int i;
230 :
231 0 : ParseAbortRecord(info, xlrec, &parsed);
232 :
233 : /* If this is a prepared xact, show the xid of the original xact */
234 0 : if (TransactionIdIsValid(parsed.twophase_xid))
235 0 : appendStringInfo(buf, "%u: ", parsed.twophase_xid);
236 :
237 0 : appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
238 0 : if (parsed.nrels > 0)
239 : {
240 0 : appendStringInfoString(buf, "; rels:");
241 0 : for (i = 0; i < parsed.nrels; i++)
242 : {
243 0 : char *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM);
244 :
245 0 : appendStringInfo(buf, " %s", path);
246 0 : pfree(path);
247 : }
248 : }
249 :
250 0 : if (parsed.nsubxacts > 0)
251 : {
252 0 : appendStringInfoString(buf, "; subxacts:");
253 0 : for (i = 0; i < parsed.nsubxacts; i++)
254 0 : appendStringInfo(buf, " %u", parsed.subxacts[i]);
255 : }
256 0 : }
257 :
258 : static void
259 0 : xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
260 : {
261 : int i;
262 :
263 0 : appendStringInfoString(buf, "subxacts:");
264 :
265 0 : for (i = 0; i < xlrec->nsubxacts; i++)
266 0 : appendStringInfo(buf, " %u", xlrec->xsub[i]);
267 0 : }
268 :
269 : void
270 0 : xact_desc(StringInfo buf, XLogReaderState *record)
271 : {
272 0 : char *rec = XLogRecGetData(record);
273 0 : uint8 info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
274 :
275 0 : if (info == XLOG_XACT_COMMIT || info == XLOG_XACT_COMMIT_PREPARED)
276 0 : {
277 0 : xl_xact_commit *xlrec = (xl_xact_commit *) rec;
278 :
279 0 : xact_desc_commit(buf, XLogRecGetInfo(record), xlrec,
280 0 : XLogRecGetOrigin(record));
281 : }
282 0 : else if (info == XLOG_XACT_ABORT || info == XLOG_XACT_ABORT_PREPARED)
283 0 : {
284 0 : xl_xact_abort *xlrec = (xl_xact_abort *) rec;
285 :
286 0 : xact_desc_abort(buf, XLogRecGetInfo(record), xlrec);
287 : }
288 0 : else if (info == XLOG_XACT_ASSIGNMENT)
289 : {
290 0 : xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
291 :
292 : /*
293 : * Note that we ignore the WAL record's xid, since we're more
294 : * interested in the top-level xid that issued the record and which
295 : * xids are being reported here.
296 : */
297 0 : appendStringInfo(buf, "xtop %u: ", xlrec->xtop);
298 0 : xact_desc_assignment(buf, xlrec);
299 : }
300 0 : }
301 :
302 : const char *
303 0 : xact_identify(uint8 info)
304 : {
305 0 : const char *id = NULL;
306 :
307 0 : switch (info & XLOG_XACT_OPMASK)
308 : {
309 : case XLOG_XACT_COMMIT:
310 0 : id = "COMMIT";
311 0 : break;
312 : case XLOG_XACT_PREPARE:
313 0 : id = "PREPARE";
314 0 : break;
315 : case XLOG_XACT_ABORT:
316 0 : id = "ABORT";
317 0 : break;
318 : case XLOG_XACT_COMMIT_PREPARED:
319 0 : id = "COMMIT_PREPARED";
320 0 : break;
321 : case XLOG_XACT_ABORT_PREPARED:
322 0 : id = "ABORT_PREPARED";
323 0 : break;
324 : case XLOG_XACT_ASSIGNMENT:
325 0 : id = "ASSIGNMENT";
326 0 : break;
327 : }
328 :
329 0 : return id;
330 : }
|