Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Make pg_waldump report more detail information about PREPARE TRANSACTION record.
authorFujii Masao <fujii@postgresql.org>
Wed, 13 Nov 2019 07:59:17 +0000 (16:59 +0900)
committerFujii Masao <fujii@postgresql.org>
Wed, 13 Nov 2019 07:59:17 +0000 (16:59 +0900)
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

src/backend/access/rmgrdesc/standbydesc.c
src/backend/access/rmgrdesc/xactdesc.c
src/backend/access/transam/twophase.c
src/include/access/twophase.h
src/include/access/xact.h

index c295358f3646ee971c48a165c5062a1b546d5886..aaff652aebcdaae138dddcff04a9af460b806a77 100644 (file)
@@ -102,6 +102,10 @@ standby_desc_invalidations(StringInfo buf,
 {
    int         i;
 
+   /* Do nothing if there are no invalidation messages */
+   if (nmsgs <= 0)
+       return;
+
    if (relcacheInitFileInval)
        appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
                         dbId, tsId);
index a61f38dd19b23bda767bd1ab88250eebfb362c68..4c411c5322e4d3a2cac4178f656bce701e6deb26 100644 (file)
@@ -209,43 +209,95 @@ ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
    }
 }
 
-static void
-xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId origin_id)
+/*
+ * ParsePrepareRecord
+ */
+void
+ParsePrepareRecord(uint8 info, xl_xact_prepare *xlrec, xl_xact_parsed_prepare *parsed)
 {
-   xl_xact_parsed_commit parsed;
-   int         i;
+   char       *bufptr;
 
-   ParseCommitRecord(info, xlrec, &parsed);
+   bufptr = ((char *) xlrec) + MAXALIGN(sizeof(xl_xact_prepare));
 
-   /* If this is a prepared xact, show the xid of the original xact */
-   if (TransactionIdIsValid(parsed.twophase_xid))
-       appendStringInfo(buf, "%u: ", parsed.twophase_xid);
+   memset(parsed, 0, sizeof(*parsed));
 
-   appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+   parsed->xact_time = xlrec->prepared_at;
+   parsed->origin_lsn = xlrec->origin_lsn;
+   parsed->origin_timestamp = xlrec->origin_timestamp;
+   parsed->twophase_xid = xlrec->xid;
+   parsed->dbId = xlrec->database;
+   parsed->nsubxacts = xlrec->nsubxacts;
+   parsed->nrels = xlrec->ncommitrels;
+   parsed->nabortrels = xlrec->nabortrels;
+   parsed->nmsgs = xlrec->ninvalmsgs;
+
+   strncpy(parsed->twophase_gid, bufptr, xlrec->gidlen);
+   bufptr += MAXALIGN(xlrec->gidlen);
+
+   parsed->subxacts = (TransactionId *) bufptr;
+   bufptr += MAXALIGN(xlrec->nsubxacts * sizeof(TransactionId));
+
+   parsed->xnodes = (RelFileNode *) bufptr;
+   bufptr += MAXALIGN(xlrec->ncommitrels * sizeof(RelFileNode));
+
+   parsed->abortnodes = (RelFileNode *) bufptr;
+   bufptr += MAXALIGN(xlrec->nabortrels * sizeof(RelFileNode));
 
-   if (parsed.nrels > 0)
+   parsed->msgs = (SharedInvalidationMessage *) bufptr;
+   bufptr += MAXALIGN(xlrec->ninvalmsgs * sizeof(SharedInvalidationMessage));
+}
+
+static void
+xact_desc_relations(StringInfo buf, char *label, int nrels,
+                   RelFileNode *xnodes)
+{
+   int     i;
+
+   if (nrels > 0)
    {
-       appendStringInfoString(buf, "; rels:");
-       for (i = 0; i < parsed.nrels; i++)
+       appendStringInfo(buf, "; %s:", label);
+       for (i = 0; i < nrels; i++)
        {
-           char       *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM);
+           char       *path = relpathperm(xnodes[i], MAIN_FORKNUM);
 
            appendStringInfo(buf, " %s", path);
            pfree(path);
        }
    }
-   if (parsed.nsubxacts > 0)
+}
+
+static void
+xact_desc_subxacts(StringInfo buf, int nsubxacts, TransactionId *subxacts)
+{
+   int     i;
+
+   if (nsubxacts > 0)
    {
        appendStringInfoString(buf, "; subxacts:");
-       for (i = 0; i < parsed.nsubxacts; i++)
-           appendStringInfo(buf, " %u", parsed.subxacts[i]);
-   }
-   if (parsed.nmsgs > 0)
-   {
-       standby_desc_invalidations(
-                                  buf, parsed.nmsgs, parsed.msgs, parsed.dbId, parsed.tsId,
-                                  XactCompletionRelcacheInitFileInval(parsed.xinfo));
+       for (i = 0; i < nsubxacts; i++)
+           appendStringInfo(buf, " %u", subxacts[i]);
    }
+}
+
+static void
+xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId origin_id)
+{
+   xl_xact_parsed_commit parsed;
+
+   ParseCommitRecord(info, xlrec, &parsed);
+
+   /* If this is a prepared xact, show the xid of the original xact */
+   if (TransactionIdIsValid(parsed.twophase_xid))
+       appendStringInfo(buf, "%u: ", parsed.twophase_xid);
+
+   appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+
+   xact_desc_relations(buf, "rels", parsed.nrels, parsed.xnodes);
+   xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
+
+   standby_desc_invalidations(
+                       buf, parsed.nmsgs, parsed.msgs, parsed.dbId, parsed.tsId,
+                       XactCompletionRelcacheInitFileInval(parsed.xinfo));
 
    if (XactCompletionForceSyncCommit(parsed.xinfo))
        appendStringInfoString(buf, "; sync");
@@ -264,7 +316,6 @@ static void
 xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
 {
    xl_xact_parsed_abort parsed;
-   int         i;
 
    ParseAbortRecord(info, xlrec, &parsed);
 
@@ -273,24 +324,29 @@ xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
        appendStringInfo(buf, "%u: ", parsed.twophase_xid);
 
    appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
-   if (parsed.nrels > 0)
-   {
-       appendStringInfoString(buf, "; rels:");
-       for (i = 0; i < parsed.nrels; i++)
-       {
-           char       *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM);
 
-           appendStringInfo(buf, " %s", path);
-           pfree(path);
-       }
-   }
+   xact_desc_relations(buf, "rels", parsed.nrels, parsed.xnodes);
+   xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
+}
 
-   if (parsed.nsubxacts > 0)
-   {
-       appendStringInfoString(buf, "; subxacts:");
-       for (i = 0; i < parsed.nsubxacts; i++)
-           appendStringInfo(buf, " %u", parsed.subxacts[i]);
-   }
+static void
+xact_desc_prepare(StringInfo buf, uint8 info, xl_xact_prepare *xlrec)
+{
+   xl_xact_parsed_prepare parsed;
+
+   ParsePrepareRecord(info, xlrec, &parsed);
+
+   appendStringInfo(buf, "gid %s: ", parsed.twophase_gid);
+   appendStringInfoString(buf, timestamptz_to_str(parsed.xact_time));
+
+   xact_desc_relations(buf, "rels(commit)", parsed.nrels, parsed.xnodes);
+   xact_desc_relations(buf, "rels(abort)", parsed.nabortrels,
+                       parsed.abortnodes);
+   xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
+
+   standby_desc_invalidations(
+                       buf, parsed.nmsgs, parsed.msgs, parsed.dbId, parsed.tsId,
+                       xlrec->initfileinval);
 }
 
 static void
@@ -323,6 +379,12 @@ xact_desc(StringInfo buf, XLogReaderState *record)
 
        xact_desc_abort(buf, XLogRecGetInfo(record), xlrec);
    }
+   else if (info == XLOG_XACT_PREPARE)
+   {
+       xl_xact_prepare *xlrec = (xl_xact_prepare *) rec;
+
+       xact_desc_prepare(buf, XLogRecGetInfo(record), xlrec);
+   }
    else if (info == XLOG_XACT_ASSIGNMENT)
    {
        xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
index 712e842b9048d22df139147102da84374cdf786e..b3ad0d08e30f85d5b09147cc45ed792598bb0a88 100644 (file)
@@ -910,23 +910,7 @@ TwoPhaseGetDummyProc(TransactionId xid, bool lock_held)
  */
 #define TWOPHASE_MAGIC 0x57F94534  /* format identifier */
 
-typedef struct TwoPhaseFileHeader
-{
-   uint32      magic;          /* format identifier */
-   uint32      total_len;      /* actual file length */
-   TransactionId xid;          /* original transaction XID */
-   Oid         database;       /* OID of database it was in */
-   TimestampTz prepared_at;    /* time of preparation */
-   Oid         owner;          /* user running the transaction */
-   int32       nsubxacts;      /* number of following subxact XIDs */
-   int32       ncommitrels;    /* number of delete-on-commit rels */
-   int32       nabortrels;     /* number of delete-on-abort rels */
-   int32       ninvalmsgs;     /* number of cache invalidation messages */
-   bool        initfileinval;  /* does relcache init file need invalidation? */
-   uint16      gidlen;         /* length of the GID - GID follows the header */
-   XLogRecPtr  origin_lsn;     /* lsn of this record at origin node */
-   TimestampTz origin_timestamp;   /* time of prepare at origin node */
-} TwoPhaseFileHeader;
+typedef xl_xact_prepare TwoPhaseFileHeader;
 
 /*
  * Header for each record in a state file
@@ -1331,44 +1315,6 @@ ReadTwoPhaseFile(TransactionId xid, bool missing_ok)
    return buf;
 }
 
-/*
- * ParsePrepareRecord
- */
-void
-ParsePrepareRecord(uint8 info, char *xlrec, xl_xact_parsed_prepare *parsed)
-{
-   TwoPhaseFileHeader *hdr;
-   char       *bufptr;
-
-   hdr = (TwoPhaseFileHeader *) xlrec;
-   bufptr = xlrec + MAXALIGN(sizeof(TwoPhaseFileHeader));
-
-   parsed->origin_lsn = hdr->origin_lsn;
-   parsed->origin_timestamp = hdr->origin_timestamp;
-   parsed->twophase_xid = hdr->xid;
-   parsed->dbId = hdr->database;
-   parsed->nsubxacts = hdr->nsubxacts;
-   parsed->nrels = hdr->ncommitrels;
-   parsed->nabortrels = hdr->nabortrels;
-   parsed->nmsgs = hdr->ninvalmsgs;
-
-   strncpy(parsed->twophase_gid, bufptr, hdr->gidlen);
-   bufptr += MAXALIGN(hdr->gidlen);
-
-   parsed->subxacts = (TransactionId *) bufptr;
-   bufptr += MAXALIGN(hdr->nsubxacts * sizeof(TransactionId));
-
-   parsed->xnodes = (RelFileNode *) bufptr;
-   bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileNode));
-
-   parsed->abortnodes = (RelFileNode *) bufptr;
-   bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileNode));
-
-   parsed->msgs = (SharedInvalidationMessage *) bufptr;
-   bufptr += MAXALIGN(hdr->ninvalmsgs * sizeof(SharedInvalidationMessage));
-}
-
-
 
 /*
  * Reads 2PC data from xlog. During checkpoint this data will be moved to
index b9a531c96e3eb48ccf6c6a1dcb931d73103b3b61..1093085a242f7d75feb4c4636437149855ee383c 100644 (file)
@@ -47,8 +47,6 @@ extern bool StandbyTransactionIdIsPrepared(TransactionId xid);
 
 extern TransactionId PrescanPreparedTransactions(TransactionId **xids_p,
                                                 int *nxids_p);
-extern void ParsePrepareRecord(uint8 info, char *xlrec,
-                              xl_xact_parsed_prepare *parsed);
 extern void StandbyRecoverPreparedTransactions(void);
 extern void RecoverPreparedTransactions(void);
 
index d7145517047c4be82534b79821888f51d0e4dcb0..42b76cb4dd3defb373275688e9921251b17dd49a 100644 (file)
@@ -292,6 +292,24 @@ typedef struct xl_xact_abort
 } xl_xact_abort;
 #define MinSizeOfXactAbort sizeof(xl_xact_abort)
 
+typedef struct xl_xact_prepare
+{
+   uint32      magic;          /* format identifier */
+   uint32      total_len;      /* actual file length */
+   TransactionId xid;          /* original transaction XID */
+   Oid         database;       /* OID of database it was in */
+   TimestampTz prepared_at;    /* time of preparation */
+   Oid         owner;          /* user running the transaction */
+   int32       nsubxacts;      /* number of following subxact XIDs */
+   int32       ncommitrels;    /* number of delete-on-commit rels */
+   int32       nabortrels;     /* number of delete-on-abort rels */
+   int32       ninvalmsgs;     /* number of cache invalidation messages */
+   bool        initfileinval;  /* does relcache init file need invalidation? */
+   uint16      gidlen;         /* length of the GID - GID follows the header */
+   XLogRecPtr  origin_lsn;     /* lsn of this record at origin node */
+   TimestampTz origin_timestamp;   /* time of prepare at origin node */
+} xl_xact_prepare;
+
 /*
  * Commit/Abort records in the above form are a bit verbose to parse, so
  * there's a deconstructed versions generated by ParseCommit/AbortRecord() for
@@ -435,6 +453,7 @@ extern const char *xact_identify(uint8 info);
 /* also in xactdesc.c, so they can be shared between front/backend code */
 extern void ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed);
 extern void ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed);
+extern void ParsePrepareRecord(uint8 info, xl_xact_prepare *xlrec, xl_xact_parsed_prepare *parsed);
 
 extern void EnterParallelMode(void);
 extern void ExitParallelMode(void);