Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7b8a899

Browse files
committed
Make pg_waldump report more detail information about PREPARE TRANSACTION record.
This commit changes xact_desc() so that it reports the detail information about PREPARE TRANSACTION record, like GID (global transaction identifier), timestamp at prepare transaction, delete-on-abort/commit relations, XID of subtransactions, and invalidation messages. These are helpful when diagnosing 2PC-related troubles. Author: Fujii Masao Reviewed-by: Michael Paquier, Andrey Lepikhov, Kyotaro Horiguchi, Julien Rouhaud, Alvaro Herrera Discussion: https://postgr.es/m/CAHGQGwEvhASad4JJnCv=0dW2TJypZgW_Vpb-oZik2a3utCqcrA@mail.gmail.com
1 parent 94fec48 commit 7b8a899

File tree

5 files changed

+125
-96
lines changed

5 files changed

+125
-96
lines changed

src/backend/access/rmgrdesc/standbydesc.c

+4
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ standby_desc_invalidations(StringInfo buf,
102102
{
103103
int i;
104104

105+
/* Do nothing if there are no invalidation messages */
106+
if (nmsgs <= 0)
107+
return;
108+
105109
if (relcacheInitFileInval)
106110
appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
107111
dbId, tsId);

src/backend/access/rmgrdesc/xactdesc.c

+101-39
Original file line numberDiff line numberDiff line change
@@ -209,43 +209,95 @@ ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
209209
}
210210
}
211211

212-
static void
213-
xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId origin_id)
212+
/*
213+
* ParsePrepareRecord
214+
*/
215+
void
216+
ParsePrepareRecord(uint8 info, xl_xact_prepare *xlrec, xl_xact_parsed_prepare *parsed)
214217
{
215-
xl_xact_parsed_commit parsed;
216-
int i;
218+
char *bufptr;
217219

218-
ParseCommitRecord(info, xlrec, &parsed);
220+
bufptr = ((char *) xlrec) + MAXALIGN(sizeof(xl_xact_prepare));
219221

220-
/* If this is a prepared xact, show the xid of the original xact */
221-
if (TransactionIdIsValid(parsed.twophase_xid))
222-
appendStringInfo(buf, "%u: ", parsed.twophase_xid);
222+
memset(parsed, 0, sizeof(*parsed));
223223

224-
appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
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));
225245

226-
if (parsed.nrels > 0)
246+
parsed->msgs = (SharedInvalidationMessage *) bufptr;
247+
bufptr += MAXALIGN(xlrec->ninvalmsgs * sizeof(SharedInvalidationMessage));
248+
}
249+
250+
static void
251+
xact_desc_relations(StringInfo buf, char *label, int nrels,
252+
RelFileNode *xnodes)
253+
{
254+
int i;
255+
256+
if (nrels > 0)
227257
{
228-
appendStringInfoString(buf, "; rels:");
229-
for (i = 0; i < parsed.nrels; i++)
258+
appendStringInfo(buf, "; %s:", label);
259+
for (i = 0; i < nrels; i++)
230260
{
231-
char *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM);
261+
char *path = relpathperm(xnodes[i], MAIN_FORKNUM);
232262

233263
appendStringInfo(buf, " %s", path);
234264
pfree(path);
235265
}
236266
}
237-
if (parsed.nsubxacts > 0)
267+
}
268+
269+
static void
270+
xact_desc_subxacts(StringInfo buf, int nsubxacts, TransactionId *subxacts)
271+
{
272+
int i;
273+
274+
if (nsubxacts > 0)
238275
{
239276
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-
{
245-
standby_desc_invalidations(
246-
buf, parsed.nmsgs, parsed.msgs, parsed.dbId, parsed.tsId,
247-
XactCompletionRelcacheInitFileInval(parsed.xinfo));
277+
for (i = 0; i < nsubxacts; i++)
278+
appendStringInfo(buf, " %u", subxacts[i]);
248279
}
280+
}
281+
282+
static void
283+
xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId origin_id)
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 */
290+
if (TransactionIdIsValid(parsed.twophase_xid))
291+
appendStringInfo(buf, "%u: ", parsed.twophase_xid);
292+
293+
appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
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(
299+
buf, parsed.nmsgs, parsed.msgs, parsed.dbId, parsed.tsId,
300+
XactCompletionRelcacheInitFileInval(parsed.xinfo));
249301

250302
if (XactCompletionForceSyncCommit(parsed.xinfo))
251303
appendStringInfoString(buf, "; sync");
@@ -264,7 +316,6 @@ static void
264316
xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
265317
{
266318
xl_xact_parsed_abort parsed;
267-
int i;
268319

269320
ParseAbortRecord(info, xlrec, &parsed);
270321

@@ -273,24 +324,29 @@ xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
273324
appendStringInfo(buf, "%u: ", parsed.twophase_xid);
274325

275326
appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
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);
282327

283-
appendStringInfo(buf, " %s", path);
284-
pfree(path);
285-
}
286-
}
328+
xact_desc_relations(buf, "rels", parsed.nrels, parsed.xnodes);
329+
xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
330+
}
287331

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-
}
332+
static void
333+
xact_desc_prepare(StringInfo buf, uint8 info, xl_xact_prepare *xlrec)
334+
{
335+
xl_xact_parsed_prepare parsed;
336+
337+
ParsePrepareRecord(info, xlrec, &parsed);
338+
339+
appendStringInfo(buf, "gid %s: ", parsed.twophase_gid);
340+
appendStringInfoString(buf, timestamptz_to_str(parsed.xact_time));
341+
342+
xact_desc_relations(buf, "rels(commit)", parsed.nrels, parsed.xnodes);
343+
xact_desc_relations(buf, "rels(abort)", parsed.nabortrels,
344+
parsed.abortnodes);
345+
xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
346+
347+
standby_desc_invalidations(
348+
buf, parsed.nmsgs, parsed.msgs, parsed.dbId, parsed.tsId,
349+
xlrec->initfileinval);
294350
}
295351

296352
static void
@@ -323,6 +379,12 @@ xact_desc(StringInfo buf, XLogReaderState *record)
323379

324380
xact_desc_abort(buf, XLogRecGetInfo(record), xlrec);
325381
}
382+
else if (info == XLOG_XACT_PREPARE)
383+
{
384+
xl_xact_prepare *xlrec = (xl_xact_prepare *) rec;
385+
386+
xact_desc_prepare(buf, XLogRecGetInfo(record), xlrec);
387+
}
326388
else if (info == XLOG_XACT_ASSIGNMENT)
327389
{
328390
xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;

src/backend/access/transam/twophase.c

+1-55
Original file line numberDiff line numberDiff line change
@@ -910,23 +910,7 @@ TwoPhaseGetDummyProc(TransactionId xid, bool lock_held)
910910
*/
911911
#define TWOPHASE_MAGIC 0x57F94534 /* format identifier */
912912

913-
typedef struct TwoPhaseFileHeader
914-
{
915-
uint32 magic; /* format identifier */
916-
uint32 total_len; /* actual file length */
917-
TransactionId xid; /* original transaction XID */
918-
Oid database; /* OID of database it was in */
919-
TimestampTz prepared_at; /* time of preparation */
920-
Oid owner; /* user running the transaction */
921-
int32 nsubxacts; /* number of following subxact XIDs */
922-
int32 ncommitrels; /* number of delete-on-commit rels */
923-
int32 nabortrels; /* number of delete-on-abort rels */
924-
int32 ninvalmsgs; /* number of cache invalidation messages */
925-
bool initfileinval; /* does relcache init file need invalidation? */
926-
uint16 gidlen; /* length of the GID - GID follows the header */
927-
XLogRecPtr origin_lsn; /* lsn of this record at origin node */
928-
TimestampTz origin_timestamp; /* time of prepare at origin node */
929-
} TwoPhaseFileHeader;
913+
typedef xl_xact_prepare TwoPhaseFileHeader;
930914

931915
/*
932916
* Header for each record in a state file
@@ -1331,44 +1315,6 @@ ReadTwoPhaseFile(TransactionId xid, bool missing_ok)
13311315
return buf;
13321316
}
13331317

1334-
/*
1335-
* ParsePrepareRecord
1336-
*/
1337-
void
1338-
ParsePrepareRecord(uint8 info, char *xlrec, xl_xact_parsed_prepare *parsed)
1339-
{
1340-
TwoPhaseFileHeader *hdr;
1341-
char *bufptr;
1342-
1343-
hdr = (TwoPhaseFileHeader *) xlrec;
1344-
bufptr = xlrec + MAXALIGN(sizeof(TwoPhaseFileHeader));
1345-
1346-
parsed->origin_lsn = hdr->origin_lsn;
1347-
parsed->origin_timestamp = hdr->origin_timestamp;
1348-
parsed->twophase_xid = hdr->xid;
1349-
parsed->dbId = hdr->database;
1350-
parsed->nsubxacts = hdr->nsubxacts;
1351-
parsed->nrels = hdr->ncommitrels;
1352-
parsed->nabortrels = hdr->nabortrels;
1353-
parsed->nmsgs = hdr->ninvalmsgs;
1354-
1355-
strncpy(parsed->twophase_gid, bufptr, hdr->gidlen);
1356-
bufptr += MAXALIGN(hdr->gidlen);
1357-
1358-
parsed->subxacts = (TransactionId *) bufptr;
1359-
bufptr += MAXALIGN(hdr->nsubxacts * sizeof(TransactionId));
1360-
1361-
parsed->xnodes = (RelFileNode *) bufptr;
1362-
bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileNode));
1363-
1364-
parsed->abortnodes = (RelFileNode *) bufptr;
1365-
bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileNode));
1366-
1367-
parsed->msgs = (SharedInvalidationMessage *) bufptr;
1368-
bufptr += MAXALIGN(hdr->ninvalmsgs * sizeof(SharedInvalidationMessage));
1369-
}
1370-
1371-
13721318

13731319
/*
13741320
* Reads 2PC data from xlog. During checkpoint this data will be moved to

src/include/access/twophase.h

-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ extern bool StandbyTransactionIdIsPrepared(TransactionId xid);
4747

4848
extern TransactionId PrescanPreparedTransactions(TransactionId **xids_p,
4949
int *nxids_p);
50-
extern void ParsePrepareRecord(uint8 info, char *xlrec,
51-
xl_xact_parsed_prepare *parsed);
5250
extern void StandbyRecoverPreparedTransactions(void);
5351
extern void RecoverPreparedTransactions(void);
5452

src/include/access/xact.h

+19
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,24 @@ typedef struct xl_xact_abort
292292
} xl_xact_abort;
293293
#define MinSizeOfXactAbort sizeof(xl_xact_abort)
294294

295+
typedef struct xl_xact_prepare
296+
{
297+
uint32 magic; /* format identifier */
298+
uint32 total_len; /* actual file length */
299+
TransactionId xid; /* original transaction XID */
300+
Oid database; /* OID of database it was in */
301+
TimestampTz prepared_at; /* time of preparation */
302+
Oid owner; /* user running the transaction */
303+
int32 nsubxacts; /* number of following subxact XIDs */
304+
int32 ncommitrels; /* number of delete-on-commit rels */
305+
int32 nabortrels; /* number of delete-on-abort rels */
306+
int32 ninvalmsgs; /* number of cache invalidation messages */
307+
bool initfileinval; /* does relcache init file need invalidation? */
308+
uint16 gidlen; /* length of the GID - GID follows the header */
309+
XLogRecPtr origin_lsn; /* lsn of this record at origin node */
310+
TimestampTz origin_timestamp; /* time of prepare at origin node */
311+
} xl_xact_prepare;
312+
295313
/*
296314
* Commit/Abort records in the above form are a bit verbose to parse, so
297315
* there's a deconstructed versions generated by ParseCommit/AbortRecord() for
@@ -435,6 +453,7 @@ extern const char *xact_identify(uint8 info);
435453
/* also in xactdesc.c, so they can be shared between front/backend code */
436454
extern void ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed);
437455
extern void ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed);
456+
extern void ParsePrepareRecord(uint8 info, xl_xact_prepare *xlrec, xl_xact_parsed_prepare *parsed);
438457

439458
extern void EnterParallelMode(void);
440459
extern void ExitParallelMode(void);

0 commit comments

Comments
 (0)