LCOV - code coverage report
Current view: top level - src/backend/access/rmgrdesc - xactdesc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 141 207 68.1 %
Date: 2021-12-04 23:09:10 Functions: 8 11 72.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * xactdesc.c
       4             :  *    rmgr descriptor routines for access/transam/xact.c
       5             :  *
       6             :  * Portions Copyright (c) 1996-2021, 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 "storage/sinval.h"
      20             : #include "storage/standbydefs.h"
      21             : #include "utils/timestamp.h"
      22             : 
      23             : /*
      24             :  * Parse the WAL format of an xact commit and abort records into an 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_waldump) 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        8006 : ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed)
      35             : {
      36        8006 :     char       *data = ((char *) xlrec) + MinSizeOfXactCommit;
      37             : 
      38        8006 :     memset(parsed, 0, sizeof(*parsed));
      39             : 
      40        8006 :     parsed->xinfo = 0;           /* default, if no XLOG_XACT_HAS_INFO is
      41             :                                  * present */
      42             : 
      43        8006 :     parsed->xact_time = xlrec->xact_time;
      44             : 
      45        8006 :     if (info & XLOG_XACT_HAS_INFO)
      46             :     {
      47        3840 :         xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data;
      48             : 
      49        3840 :         parsed->xinfo = xl_xinfo->xinfo;
      50             : 
      51        3840 :         data += sizeof(xl_xact_xinfo);
      52             :     }
      53             : 
      54        8006 :     if (parsed->xinfo & XACT_XINFO_HAS_DBINFO)
      55             :     {
      56        3718 :         xl_xact_dbinfo *xl_dbinfo = (xl_xact_dbinfo *) data;
      57             : 
      58        3718 :         parsed->dbId = xl_dbinfo->dbId;
      59        3718 :         parsed->tsId = xl_dbinfo->tsId;
      60             : 
      61        3718 :         data += sizeof(xl_xact_dbinfo);
      62             :     }
      63             : 
      64        8006 :     if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS)
      65             :     {
      66         426 :         xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data;
      67             : 
      68         426 :         parsed->nsubxacts = xl_subxacts->nsubxacts;
      69         426 :         parsed->subxacts = xl_subxacts->subxacts;
      70             : 
      71         426 :         data += MinSizeOfXactSubxacts;
      72         426 :         data += parsed->nsubxacts * sizeof(TransactionId);
      73             :     }
      74             : 
      75        8006 :     if (parsed->xinfo & XACT_XINFO_HAS_RELFILENODES)
      76             :     {
      77         344 :         xl_xact_relfilenodes *xl_relfilenodes = (xl_xact_relfilenodes *) data;
      78             : 
      79         344 :         parsed->nrels = xl_relfilenodes->nrels;
      80         344 :         parsed->xnodes = xl_relfilenodes->xnodes;
      81             : 
      82         344 :         data += MinSizeOfXactRelfilenodes;
      83         344 :         data += xl_relfilenodes->nrels * sizeof(RelFileNode);
      84             :     }
      85             : 
      86        8006 :     if (parsed->xinfo & XACT_XINFO_HAS_INVALS)
      87             :     {
      88        1602 :         xl_xact_invals *xl_invals = (xl_xact_invals *) data;
      89             : 
      90        1602 :         parsed->nmsgs = xl_invals->nmsgs;
      91        1602 :         parsed->msgs = xl_invals->msgs;
      92             : 
      93        1602 :         data += MinSizeOfXactInvals;
      94        1602 :         data += xl_invals->nmsgs * sizeof(SharedInvalidationMessage);
      95             :     }
      96             : 
      97        8006 :     if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE)
      98             :     {
      99         264 :         xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data;
     100             : 
     101         264 :         parsed->twophase_xid = xl_twophase->xid;
     102             : 
     103         264 :         data += sizeof(xl_xact_twophase);
     104             : 
     105         264 :         if (parsed->xinfo & XACT_XINFO_HAS_GID)
     106             :         {
     107         156 :             strlcpy(parsed->twophase_gid, data, sizeof(parsed->twophase_gid));
     108         156 :             data += strlen(data) + 1;
     109             :         }
     110             :     }
     111             : 
     112             :     /* Note: no alignment is guaranteed after this point */
     113             : 
     114        8006 :     if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
     115             :     {
     116             :         xl_xact_origin xl_origin;
     117             : 
     118             :         /* no alignment is guaranteed, so copy onto stack */
     119          62 :         memcpy(&xl_origin, data, sizeof(xl_origin));
     120             : 
     121          62 :         parsed->origin_lsn = xl_origin.origin_lsn;
     122          62 :         parsed->origin_timestamp = xl_origin.origin_timestamp;
     123             : 
     124          62 :         data += sizeof(xl_xact_origin);
     125             :     }
     126        8006 : }
     127             : 
     128             : void
     129         220 : ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
     130             : {
     131         220 :     char       *data = ((char *) xlrec) + MinSizeOfXactAbort;
     132             : 
     133         220 :     memset(parsed, 0, sizeof(*parsed));
     134             : 
     135         220 :     parsed->xinfo = 0;           /* default, if no XLOG_XACT_HAS_INFO is
     136             :                                  * present */
     137             : 
     138         220 :     parsed->xact_time = xlrec->xact_time;
     139             : 
     140         220 :     if (info & XLOG_XACT_HAS_INFO)
     141             :     {
     142         170 :         xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data;
     143             : 
     144         170 :         parsed->xinfo = xl_xinfo->xinfo;
     145             : 
     146         170 :         data += sizeof(xl_xact_xinfo);
     147             :     }
     148             : 
     149         220 :     if (parsed->xinfo & XACT_XINFO_HAS_DBINFO)
     150             :     {
     151          68 :         xl_xact_dbinfo *xl_dbinfo = (xl_xact_dbinfo *) data;
     152             : 
     153          68 :         parsed->dbId = xl_dbinfo->dbId;
     154          68 :         parsed->tsId = xl_dbinfo->tsId;
     155             : 
     156          68 :         data += sizeof(xl_xact_dbinfo);
     157             :     }
     158             : 
     159         220 :     if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS)
     160             :     {
     161          18 :         xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data;
     162             : 
     163          18 :         parsed->nsubxacts = xl_subxacts->nsubxacts;
     164          18 :         parsed->subxacts = xl_subxacts->subxacts;
     165             : 
     166          18 :         data += MinSizeOfXactSubxacts;
     167          18 :         data += parsed->nsubxacts * sizeof(TransactionId);
     168             :     }
     169             : 
     170         220 :     if (parsed->xinfo & XACT_XINFO_HAS_RELFILENODES)
     171             :     {
     172          48 :         xl_xact_relfilenodes *xl_relfilenodes = (xl_xact_relfilenodes *) data;
     173             : 
     174          48 :         parsed->nrels = xl_relfilenodes->nrels;
     175          48 :         parsed->xnodes = xl_relfilenodes->xnodes;
     176             : 
     177          48 :         data += MinSizeOfXactRelfilenodes;
     178          48 :         data += xl_relfilenodes->nrels * sizeof(RelFileNode);
     179             :     }
     180             : 
     181         220 :     if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE)
     182             :     {
     183          92 :         xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data;
     184             : 
     185          92 :         parsed->twophase_xid = xl_twophase->xid;
     186             : 
     187          92 :         data += sizeof(xl_xact_twophase);
     188             : 
     189          92 :         if (parsed->xinfo & XACT_XINFO_HAS_GID)
     190             :         {
     191          68 :             strlcpy(parsed->twophase_gid, data, sizeof(parsed->twophase_gid));
     192          68 :             data += strlen(data) + 1;
     193             :         }
     194             :     }
     195             : 
     196             :     /* Note: no alignment is guaranteed after this point */
     197             : 
     198         220 :     if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
     199             :     {
     200             :         xl_xact_origin xl_origin;
     201             : 
     202             :         /* no alignment is guaranteed, so copy onto stack */
     203          10 :         memcpy(&xl_origin, data, sizeof(xl_origin));
     204             : 
     205          10 :         parsed->origin_lsn = xl_origin.origin_lsn;
     206          10 :         parsed->origin_timestamp = xl_origin.origin_timestamp;
     207             : 
     208          10 :         data += sizeof(xl_xact_origin);
     209             :     }
     210         220 : }
     211             : 
     212             : /*
     213             :  * ParsePrepareRecord
     214             :  */
     215             : void
     216         224 : ParsePrepareRecord(uint8 info, xl_xact_prepare *xlrec, xl_xact_parsed_prepare *parsed)
     217             : {
     218             :     char       *bufptr;
     219             : 
     220         224 :     bufptr = ((char *) xlrec) + MAXALIGN(sizeof(xl_xact_prepare));
     221             : 
     222         224 :     memset(parsed, 0, sizeof(*parsed));
     223             : 
     224         224 :     parsed->xact_time = xlrec->prepared_at;
     225         224 :     parsed->origin_lsn = xlrec->origin_lsn;
     226         224 :     parsed->origin_timestamp = xlrec->origin_timestamp;
     227         224 :     parsed->twophase_xid = xlrec->xid;
     228         224 :     parsed->dbId = xlrec->database;
     229         224 :     parsed->nsubxacts = xlrec->nsubxacts;
     230         224 :     parsed->nrels = xlrec->ncommitrels;
     231         224 :     parsed->nabortrels = xlrec->nabortrels;
     232         224 :     parsed->nmsgs = xlrec->ninvalmsgs;
     233             : 
     234         224 :     strncpy(parsed->twophase_gid, bufptr, xlrec->gidlen);
     235         224 :     bufptr += MAXALIGN(xlrec->gidlen);
     236             : 
     237         224 :     parsed->subxacts = (TransactionId *) bufptr;
     238         224 :     bufptr += MAXALIGN(xlrec->nsubxacts * sizeof(TransactionId));
     239             : 
     240         224 :     parsed->xnodes = (RelFileNode *) bufptr;
     241         224 :     bufptr += MAXALIGN(xlrec->ncommitrels * sizeof(RelFileNode));
     242             : 
     243         224 :     parsed->abortnodes = (RelFileNode *) bufptr;
     244         224 :     bufptr += MAXALIGN(xlrec->nabortrels * sizeof(RelFileNode));
     245             : 
     246         224 :     parsed->msgs = (SharedInvalidationMessage *) bufptr;
     247         224 :     bufptr += MAXALIGN(xlrec->ninvalmsgs * sizeof(SharedInvalidationMessage));
     248         224 : }
     249             : 
     250             : static void
     251           2 : xact_desc_relations(StringInfo buf, char *label, int nrels,
     252             :                     RelFileNode *xnodes)
     253             : {
     254             :     int         i;
     255             : 
     256           2 :     if (nrels > 0)
     257             :     {
     258           0 :         appendStringInfo(buf, "; %s:", label);
     259           0 :         for (i = 0; i < nrels; i++)
     260             :         {
     261           0 :             char       *path = relpathperm(xnodes[i], MAIN_FORKNUM);
     262             : 
     263           0 :             appendStringInfo(buf, " %s", path);
     264           0 :             pfree(path);
     265             :         }
     266             :     }
     267           2 : }
     268             : 
     269             : static void
     270           2 : xact_desc_subxacts(StringInfo buf, int nsubxacts, TransactionId *subxacts)
     271             : {
     272             :     int         i;
     273             : 
     274           2 :     if (nsubxacts > 0)
     275             :     {
     276           0 :         appendStringInfoString(buf, "; subxacts:");
     277           0 :         for (i = 0; i < nsubxacts; i++)
     278           0 :             appendStringInfo(buf, " %u", subxacts[i]);
     279             :     }
     280           2 : }
     281             : 
     282             : static void
     283           2 : xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId origin_id)
     284             : {
     285             :     xl_xact_parsed_commit parsed;
     286             : 
     287           2 :     ParseCommitRecord(info, xlrec, &parsed);
     288             : 
     289             :     /* If this is a prepared xact, show the xid of the original xact */
     290           2 :     if (TransactionIdIsValid(parsed.twophase_xid))
     291           0 :         appendStringInfo(buf, "%u: ", parsed.twophase_xid);
     292             : 
     293           2 :     appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
     294             : 
     295           2 :     xact_desc_relations(buf, "rels", parsed.nrels, parsed.xnodes);
     296           2 :     xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
     297             : 
     298           2 :     standby_desc_invalidations(buf, parsed.nmsgs, parsed.msgs, parsed.dbId,
     299             :                                parsed.tsId,
     300           2 :                                XactCompletionRelcacheInitFileInval(parsed.xinfo));
     301             : 
     302           2 :     if (XactCompletionForceSyncCommit(parsed.xinfo))
     303           2 :         appendStringInfoString(buf, "; sync");
     304             : 
     305           2 :     if (parsed.xinfo & XACT_XINFO_HAS_ORIGIN)
     306             :     {
     307           0 :         appendStringInfo(buf, "; origin: node %u, lsn %X/%X, at %s",
     308             :                          origin_id,
     309           0 :                          LSN_FORMAT_ARGS(parsed.origin_lsn),
     310             :                          timestamptz_to_str(parsed.origin_timestamp));
     311             :     }
     312           2 : }
     313             : 
     314             : static void
     315           0 : xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
     316             : {
     317             :     xl_xact_parsed_abort parsed;
     318             : 
     319           0 :     ParseAbortRecord(info, xlrec, &parsed);
     320             : 
     321             :     /* If this is a prepared xact, show the xid of the original xact */
     322           0 :     if (TransactionIdIsValid(parsed.twophase_xid))
     323           0 :         appendStringInfo(buf, "%u: ", parsed.twophase_xid);
     324             : 
     325           0 :     appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
     326             : 
     327           0 :     xact_desc_relations(buf, "rels", parsed.nrels, parsed.xnodes);
     328           0 :     xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
     329           0 : }
     330             : 
     331             : static void
     332           0 : xact_desc_prepare(StringInfo buf, uint8 info, xl_xact_prepare *xlrec)
     333             : {
     334             :     xl_xact_parsed_prepare parsed;
     335             : 
     336           0 :     ParsePrepareRecord(info, xlrec, &parsed);
     337             : 
     338           0 :     appendStringInfo(buf, "gid %s: ", parsed.twophase_gid);
     339           0 :     appendStringInfoString(buf, timestamptz_to_str(parsed.xact_time));
     340             : 
     341           0 :     xact_desc_relations(buf, "rels(commit)", parsed.nrels, parsed.xnodes);
     342           0 :     xact_desc_relations(buf, "rels(abort)", parsed.nabortrels,
     343             :                         parsed.abortnodes);
     344           0 :     xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
     345             : 
     346           0 :     standby_desc_invalidations(buf, parsed.nmsgs, parsed.msgs, parsed.dbId,
     347           0 :                                parsed.tsId, xlrec->initfileinval);
     348           0 : }
     349             : 
     350             : static void
     351           0 : xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
     352             : {
     353             :     int         i;
     354             : 
     355           0 :     appendStringInfoString(buf, "subxacts:");
     356             : 
     357           0 :     for (i = 0; i < xlrec->nsubxacts; i++)
     358           0 :         appendStringInfo(buf, " %u", xlrec->xsub[i]);
     359           0 : }
     360             : 
     361             : void
     362           2 : xact_desc(StringInfo buf, XLogReaderState *record)
     363             : {
     364           2 :     char       *rec = XLogRecGetData(record);
     365           2 :     uint8       info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
     366             : 
     367           2 :     if (info == XLOG_XACT_COMMIT || info == XLOG_XACT_COMMIT_PREPARED)
     368           2 :     {
     369           2 :         xl_xact_commit *xlrec = (xl_xact_commit *) rec;
     370             : 
     371           2 :         xact_desc_commit(buf, XLogRecGetInfo(record), xlrec,
     372           2 :                          XLogRecGetOrigin(record));
     373             :     }
     374           0 :     else if (info == XLOG_XACT_ABORT || info == XLOG_XACT_ABORT_PREPARED)
     375           0 :     {
     376           0 :         xl_xact_abort *xlrec = (xl_xact_abort *) rec;
     377             : 
     378           0 :         xact_desc_abort(buf, XLogRecGetInfo(record), xlrec);
     379             :     }
     380           0 :     else if (info == XLOG_XACT_PREPARE)
     381             :     {
     382           0 :         xl_xact_prepare *xlrec = (xl_xact_prepare *) rec;
     383             : 
     384           0 :         xact_desc_prepare(buf, XLogRecGetInfo(record), xlrec);
     385             :     }
     386           0 :     else if (info == XLOG_XACT_ASSIGNMENT)
     387             :     {
     388           0 :         xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
     389             : 
     390             :         /*
     391             :          * Note that we ignore the WAL record's xid, since we're more
     392             :          * interested in the top-level xid that issued the record and which
     393             :          * xids are being reported here.
     394             :          */
     395           0 :         appendStringInfo(buf, "xtop %u: ", xlrec->xtop);
     396           0 :         xact_desc_assignment(buf, xlrec);
     397             :     }
     398           0 :     else if (info == XLOG_XACT_INVALIDATIONS)
     399             :     {
     400           0 :         xl_xact_invals *xlrec = (xl_xact_invals *) rec;
     401             : 
     402           0 :         standby_desc_invalidations(buf, xlrec->nmsgs, xlrec->msgs, InvalidOid,
     403             :                                    InvalidOid, false);
     404             :     }
     405           2 : }
     406             : 
     407             : const char *
     408           2 : xact_identify(uint8 info)
     409             : {
     410           2 :     const char *id = NULL;
     411             : 
     412           2 :     switch (info & XLOG_XACT_OPMASK)
     413             :     {
     414           2 :         case XLOG_XACT_COMMIT:
     415           2 :             id = "COMMIT";
     416           2 :             break;
     417           0 :         case XLOG_XACT_PREPARE:
     418           0 :             id = "PREPARE";
     419           0 :             break;
     420           0 :         case XLOG_XACT_ABORT:
     421           0 :             id = "ABORT";
     422           0 :             break;
     423           0 :         case XLOG_XACT_COMMIT_PREPARED:
     424           0 :             id = "COMMIT_PREPARED";
     425           0 :             break;
     426           0 :         case XLOG_XACT_ABORT_PREPARED:
     427           0 :             id = "ABORT_PREPARED";
     428           0 :             break;
     429           0 :         case XLOG_XACT_ASSIGNMENT:
     430           0 :             id = "ASSIGNMENT";
     431           0 :             break;
     432           0 :         case XLOG_XACT_INVALIDATIONS:
     433           0 :             id = "INVALIDATION";
     434           0 :             break;
     435             :     }
     436             : 
     437           2 :     return id;
     438             : }

Generated by: LCOV version 1.14