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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 101 additions & 39 deletions
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

Lines changed: 1 addition & 55 deletions
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

Lines changed: 0 additions & 2 deletions
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

Lines changed: 19 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy