Skip to content

Commit 4f1b890

Browse files
committed
Merge the various forms of transaction commit & abort records.
Since 465883b two versions of commit records have existed. A compact version that was used when no cache invalidations, smgr unlinks and similar were needed, and a full version that could deal with all that. Additionally the full version was embedded into twophase commit records. That resulted in a measurable reduction in the size of the logged WAL in some workloads. But more recently additions like logical decoding, which e.g. needs information about the database something was executed on, made it applicable in fewer situations. The static split generally made it hard to expand the commit record, because concerns over the size made it hard to add anything to the compact version. Additionally it's not particularly pretty to have twophase.c insert RM_XACT records. Rejigger things so that the commit and abort records only have one form each, including the twophase equivalents. The presence of the various optional (in the sense of not being in every record) pieces is indicated by a bits in the 'xinfo' flag. That flag previously was not included in compact commit records. To prevent an increase in size due to its presence, it's only included if necessary; signalled by a bit in the xl_info bits available for xact.c, similar to heapam.c's XLOG_HEAP_OPMASK/XLOG_HEAP_INIT_PAGE. Twophase commit/aborts are now the same as their normal counterparts. The original transaction's xid is included in an optional data field. This means that commit records generally are smaller, except in the case of a transaction with subtransactions, but no other special cases; the increase there is four bytes, which seems acceptable given that the more common case of not having subtransactions shrank. The savings are especially measurable for twophase commits, which previously always used the full version; but will in practice only infrequently have required that. The motivation for this work are not the space savings and and deduplication though; it's that it makes it easier to extend commit records with additional information. That's just a few lines of code now; without impacting the common case where that information is not needed. Discussion: 20150220152150.GD4149@awork2.anarazel.de, 235610.92468.qm%40web29004.mail.ird.yahoo.com Reviewed-By: Heikki Linnakangas, Simon Riggs
1 parent a0f5954 commit 4f1b890

File tree

7 files changed

+748
-507
lines changed

7 files changed

+748
-507
lines changed

src/backend/access/rmgrdesc/xactdesc.c

Lines changed: 175 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -14,53 +14,188 @@
1414
*/
1515
#include "postgres.h"
1616

17+
#include "access/transam.h"
1718
#include "access/xact.h"
1819
#include "catalog/catalog.h"
1920
#include "storage/sinval.h"
2021
#include "utils/timestamp.h"
2122

23+
/*
24+
* Parse the WAL format of a xact commit and abort records into a 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_xlogdump) 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
34+
ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed)
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 present */
41+
42+
parsed->xact_time = xlrec->xact_time;
43+
44+
if (info & XLOG_XACT_HAS_INFO)
45+
{
46+
xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data;
47+
48+
parsed->xinfo = xl_xinfo->xinfo;
49+
50+
data += sizeof(xl_xact_xinfo);
51+
}
52+
53+
if (parsed->xinfo & XACT_XINFO_HAS_DBINFO)
54+
{
55+
xl_xact_dbinfo *xl_dbinfo = (xl_xact_dbinfo *) data;
56+
57+
parsed->dbId = xl_dbinfo->dbId;
58+
parsed->tsId = xl_dbinfo->tsId;
59+
60+
data += sizeof(xl_xact_dbinfo);
61+
}
62+
63+
if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS)
64+
{
65+
xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data;
66+
67+
parsed->nsubxacts = xl_subxacts->nsubxacts;
68+
parsed->subxacts = xl_subxacts->subxacts;
69+
70+
data += MinSizeOfXactSubxacts;
71+
data += parsed->nsubxacts * sizeof(TransactionId);
72+
}
73+
74+
if (parsed->xinfo & XACT_XINFO_HAS_RELFILENODES)
75+
{
76+
xl_xact_relfilenodes *xl_relfilenodes = (xl_xact_relfilenodes *) data;
77+
78+
parsed->nrels = xl_relfilenodes->nrels;
79+
parsed->xnodes = xl_relfilenodes->xnodes;
80+
81+
data += MinSizeOfXactRelfilenodes;
82+
data += xl_relfilenodes->nrels * sizeof(RelFileNode);
83+
}
84+
85+
if (parsed->xinfo & XACT_XINFO_HAS_INVALS)
86+
{
87+
xl_xact_invals *xl_invals = (xl_xact_invals *) data;
88+
89+
parsed->nmsgs = xl_invals->nmsgs;
90+
parsed->msgs = xl_invals->msgs;
91+
92+
data += MinSizeOfXactInvals;
93+
data += xl_invals->nmsgs * sizeof(SharedInvalidationMessage);
94+
}
95+
96+
if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE)
97+
{
98+
xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data;
99+
100+
parsed->twophase_xid = xl_twophase->xid;
101+
102+
data += sizeof(xl_xact_twophase);
103+
}
104+
}
105+
106+
void
107+
ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
108+
{
109+
char *data = ((char *) xlrec) + MinSizeOfXactAbort;
110+
111+
memset(parsed, 0, sizeof(*parsed));
112+
113+
parsed->xinfo = 0; /* default, if no XLOG_XACT_HAS_INFO is present */
114+
115+
parsed->xact_time = xlrec->xact_time;
116+
117+
if (info & XLOG_XACT_HAS_INFO)
118+
{
119+
xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data;
120+
121+
parsed->xinfo = xl_xinfo->xinfo;
122+
123+
data += sizeof(xl_xact_xinfo);
124+
}
125+
126+
if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS)
127+
{
128+
xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data;
129+
130+
parsed->nsubxacts = xl_subxacts->nsubxacts;
131+
parsed->subxacts = xl_subxacts->subxacts;
132+
133+
data += MinSizeOfXactSubxacts;
134+
data += parsed->nsubxacts * sizeof(TransactionId);
135+
}
136+
137+
if (parsed->xinfo & XACT_XINFO_HAS_RELFILENODES)
138+
{
139+
xl_xact_relfilenodes *xl_relfilenodes = (xl_xact_relfilenodes *) data;
140+
141+
parsed->nrels = xl_relfilenodes->nrels;
142+
parsed->xnodes = xl_relfilenodes->xnodes;
143+
144+
data += MinSizeOfXactRelfilenodes;
145+
data += xl_relfilenodes->nrels * sizeof(RelFileNode);
146+
}
147+
148+
if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE)
149+
{
150+
xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data;
151+
152+
parsed->twophase_xid = xl_twophase->xid;
153+
154+
data += sizeof(xl_xact_twophase);
155+
}
156+
}
22157

23158
static void
24-
xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
159+
xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec)
25160
{
161+
xl_xact_parsed_commit parsed;
26162
int i;
27-
TransactionId *subxacts;
28163

29-
subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels];
164+
ParseCommitRecord(info, xlrec, &parsed);
165+
166+
/* If this is a prepared xact, show the xid of the original xact */
167+
if (TransactionIdIsValid(parsed.twophase_xid))
168+
appendStringInfo(buf, "%u: ", parsed.twophase_xid);
30169

31170
appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
32171

33-
if (xlrec->nrels > 0)
172+
if (parsed.nrels > 0)
34173
{
35174
appendStringInfoString(buf, "; rels:");
36-
for (i = 0; i < xlrec->nrels; i++)
175+
for (i = 0; i < parsed.nrels; i++)
37176
{
38-
char *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
177+
char *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM);
39178

40179
appendStringInfo(buf, " %s", path);
41180
pfree(path);
42181
}
43182
}
44-
if (xlrec->nsubxacts > 0)
183+
if (parsed.nsubxacts > 0)
45184
{
46185
appendStringInfoString(buf, "; subxacts:");
47-
for (i = 0; i < xlrec->nsubxacts; i++)
48-
appendStringInfo(buf, " %u", subxacts[i]);
186+
for (i = 0; i < parsed.nsubxacts; i++)
187+
appendStringInfo(buf, " %u", parsed.subxacts[i]);
49188
}
50-
if (xlrec->nmsgs > 0)
189+
if (parsed.nmsgs > 0)
51190
{
52-
SharedInvalidationMessage *msgs;
53-
54-
msgs = (SharedInvalidationMessage *) &subxacts[xlrec->nsubxacts];
55-
56-
if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
191+
if (XactCompletionRelcacheInitFileInval(parsed.xinfo))
57192
appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
58-
xlrec->dbId, xlrec->tsId);
193+
parsed.dbId, parsed.tsId);
59194

60195
appendStringInfoString(buf, "; inval msgs:");
61-
for (i = 0; i < xlrec->nmsgs; i++)
196+
for (i = 0; i < parsed.nmsgs; i++)
62197
{
63-
SharedInvalidationMessage *msg = &msgs[i];
198+
SharedInvalidationMessage *msg = &parsed.msgs[i];
64199

65200
if (msg->id >= 0)
66201
appendStringInfo(buf, " catcache %d", msg->id);
@@ -80,48 +215,41 @@ xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
80215
appendStringInfo(buf, " unknown id %d", msg->id);
81216
}
82217
}
218+
219+
if (XactCompletionForceSyncCommit(parsed.xinfo))
220+
appendStringInfo(buf, "; sync");
83221
}
84222

85223
static void
86-
xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
224+
xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
87225
{
226+
xl_xact_parsed_abort parsed;
88227
int i;
89228

90-
appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
229+
ParseAbortRecord(info, xlrec, &parsed);
91230

92-
if (xlrec->nsubxacts > 0)
93-
{
94-
appendStringInfoString(buf, "; subxacts:");
95-
for (i = 0; i < xlrec->nsubxacts; i++)
96-
appendStringInfo(buf, " %u", xlrec->subxacts[i]);
97-
}
98-
}
99-
100-
static void
101-
xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
102-
{
103-
int i;
231+
/* If this is a prepared xact, show the xid of the original xact */
232+
if (TransactionIdIsValid(parsed.twophase_xid))
233+
appendStringInfo(buf, "%u: ", parsed.twophase_xid);
104234

105235
appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
106-
if (xlrec->nrels > 0)
236+
if (parsed.nrels > 0)
107237
{
108238
appendStringInfoString(buf, "; rels:");
109-
for (i = 0; i < xlrec->nrels; i++)
239+
for (i = 0; i < parsed.nrels; i++)
110240
{
111-
char *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
241+
char *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM);
112242

113243
appendStringInfo(buf, " %s", path);
114244
pfree(path);
115245
}
116246
}
117-
if (xlrec->nsubxacts > 0)
118-
{
119-
TransactionId *xacts = (TransactionId *)
120-
&xlrec->xnodes[xlrec->nrels];
121247

248+
if (parsed.nsubxacts > 0)
249+
{
122250
appendStringInfoString(buf, "; subxacts:");
123-
for (i = 0; i < xlrec->nsubxacts; i++)
124-
appendStringInfo(buf, " %u", xacts[i]);
251+
for (i = 0; i < parsed.nsubxacts; i++)
252+
appendStringInfo(buf, " %u", parsed.subxacts[i]);
125253
}
126254
}
127255

@@ -140,39 +268,19 @@ void
140268
xact_desc(StringInfo buf, XLogReaderState *record)
141269
{
142270
char *rec = XLogRecGetData(record);
143-
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
144-
145-
if (info == XLOG_XACT_COMMIT_COMPACT)
146-
{
147-
xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
271+
uint8 info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
148272

149-
xact_desc_commit_compact(buf, xlrec);
150-
}
151-
else if (info == XLOG_XACT_COMMIT)
273+
if (info == XLOG_XACT_COMMIT || info == XLOG_XACT_COMMIT_PREPARED)
152274
{
153275
xl_xact_commit *xlrec = (xl_xact_commit *) rec;
154276

155-
xact_desc_commit(buf, xlrec);
277+
xact_desc_commit(buf, XLogRecGetInfo(record), xlrec);
156278
}
157-
else if (info == XLOG_XACT_ABORT)
279+
else if (info == XLOG_XACT_ABORT || info == XLOG_XACT_ABORT_PREPARED)
158280
{
159281
xl_xact_abort *xlrec = (xl_xact_abort *) rec;
160282

161-
xact_desc_abort(buf, xlrec);
162-
}
163-
else if (info == XLOG_XACT_COMMIT_PREPARED)
164-
{
165-
xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
166-
167-
appendStringInfo(buf, "%u: ", xlrec->xid);
168-
xact_desc_commit(buf, &xlrec->crec);
169-
}
170-
else if (info == XLOG_XACT_ABORT_PREPARED)
171-
{
172-
xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
173-
174-
appendStringInfo(buf, "%u: ", xlrec->xid);
175-
xact_desc_abort(buf, &xlrec->arec);
283+
xact_desc_abort(buf, XLogRecGetInfo(record), xlrec);
176284
}
177285
else if (info == XLOG_XACT_ASSIGNMENT)
178286
{
@@ -193,7 +301,7 @@ xact_identify(uint8 info)
193301
{
194302
const char *id = NULL;
195303

196-
switch (info & ~XLR_INFO_MASK)
304+
switch (info & XLOG_XACT_OPMASK)
197305
{
198306
case XLOG_XACT_COMMIT:
199307
id = "COMMIT";
@@ -213,9 +321,6 @@ xact_identify(uint8 info)
213321
case XLOG_XACT_ASSIGNMENT:
214322
id = "ASSIGNMENT";
215323
break;
216-
case XLOG_XACT_COMMIT_COMPACT:
217-
id = "COMMIT_COMPACT";
218-
break;
219324
}
220325

221326
return id;

0 commit comments

Comments
 (0)