LCOV - code coverage report
Current view: top level - src/backend/access/rmgrdesc - xlogdesc.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 59.8 % 179 107
Test Date: 2026-04-07 14:16:30 Functions: 71.4 % 7 5
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * xlogdesc.c
       4              :  *    rmgr descriptor routines for access/transam/xlog.c
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/access/rmgrdesc/xlogdesc.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #include "postgres.h"
      16              : 
      17              : #include "access/transam.h"
      18              : #include "access/xlog.h"
      19              : #include "access/xlog_internal.h"
      20              : #include "catalog/pg_control.h"
      21              : #include "storage/checksum.h"
      22              : #include "utils/guc.h"
      23              : #include "utils/timestamp.h"
      24              : 
      25              : /*
      26              :  * GUC support
      27              :  */
      28              : const struct config_enum_entry wal_level_options[] = {
      29              :     {"minimal", WAL_LEVEL_MINIMAL, false},
      30              :     {"replica", WAL_LEVEL_REPLICA, false},
      31              :     {"archive", WAL_LEVEL_REPLICA, true}, /* deprecated */
      32              :     {"hot_standby", WAL_LEVEL_REPLICA, true}, /* deprecated */
      33              :     {"logical", WAL_LEVEL_LOGICAL, false},
      34              :     {NULL, 0, false}
      35              : };
      36              : 
      37              : /*
      38              :  * Find a string representation for wal_level
      39              :  */
      40              : static const char *
      41           11 : get_wal_level_string(int wal_level)
      42              : {
      43              :     const struct config_enum_entry *entry;
      44           11 :     const char *wal_level_str = "?";
      45              : 
      46           29 :     for (entry = wal_level_options; entry->name; entry++)
      47              :     {
      48           29 :         if (entry->val == wal_level)
      49              :         {
      50           11 :             wal_level_str = entry->name;
      51           11 :             break;
      52              :         }
      53              :     }
      54              : 
      55           11 :     return wal_level_str;
      56              : }
      57              : 
      58              : const char *
      59            8 : get_checksum_state_string(uint32 state)
      60              : {
      61            8 :     switch (state)
      62              :     {
      63            8 :         case PG_DATA_CHECKSUM_VERSION:
      64            8 :             return "on";
      65            0 :         case PG_DATA_CHECKSUM_INPROGRESS_OFF:
      66            0 :             return "inprogress-off";
      67            0 :         case PG_DATA_CHECKSUM_INPROGRESS_ON:
      68            0 :             return "inprogress-on";
      69            0 :         case PG_DATA_CHECKSUM_OFF:
      70            0 :             return "off";
      71              :     }
      72              : 
      73              :     Assert(false);
      74            0 :     return "?";
      75              : }
      76              : 
      77              : void
      78            0 : xlog2_desc(StringInfo buf, XLogReaderState *record)
      79              : {
      80            0 :     char       *rec = XLogRecGetData(record);
      81            0 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
      82              : 
      83            0 :     if (info == XLOG2_CHECKSUMS)
      84              :     {
      85              :         xl_checksum_state xlrec;
      86              : 
      87            0 :         memcpy(&xlrec, rec, sizeof(xl_checksum_state));
      88            0 :         appendStringInfoString(buf, get_checksum_state_string(xlrec.new_checksum_state));
      89              :     }
      90            0 : }
      91              : 
      92              : void
      93          101 : xlog_desc(StringInfo buf, XLogReaderState *record)
      94              : {
      95          101 :     char       *rec = XLogRecGetData(record);
      96          101 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
      97              : 
      98          101 :     if (info == XLOG_CHECKPOINT_SHUTDOWN ||
      99              :         info == XLOG_CHECKPOINT_ONLINE)
     100            7 :     {
     101            7 :         CheckPoint *checkpoint = (CheckPoint *) rec;
     102              : 
     103           21 :         appendStringInfo(buf, "redo %X/%08X; "
     104              :                          "tli %u; prev tli %u; fpw %s; wal_level %s; logical decoding %s; xid %u:%u; oid %u; multi %u; offset %" PRIu64 "; "
     105              :                          "oldest xid %u in DB %u; oldest multi %u in DB %u; "
     106              :                          "oldest/newest commit timestamp xid: %u/%u; "
     107              :                          "oldest running xid %u; "
     108              :                          "checksums %s; %s",
     109            7 :                          LSN_FORMAT_ARGS(checkpoint->redo),
     110              :                          checkpoint->ThisTimeLineID,
     111              :                          checkpoint->PrevTimeLineID,
     112            7 :                          checkpoint->fullPageWrites ? "true" : "false",
     113              :                          get_wal_level_string(checkpoint->wal_level),
     114            7 :                          checkpoint->logicalDecodingEnabled ? "true" : "false",
     115            7 :                          EpochFromFullTransactionId(checkpoint->nextXid),
     116            7 :                          XidFromFullTransactionId(checkpoint->nextXid),
     117              :                          checkpoint->nextOid,
     118              :                          checkpoint->nextMulti,
     119              :                          checkpoint->nextMultiOffset,
     120              :                          checkpoint->oldestXid,
     121              :                          checkpoint->oldestXidDB,
     122              :                          checkpoint->oldestMulti,
     123              :                          checkpoint->oldestMultiDB,
     124              :                          checkpoint->oldestCommitTsXid,
     125              :                          checkpoint->newestCommitTsXid,
     126              :                          checkpoint->oldestActiveXid,
     127              :                          get_checksum_state_string(checkpoint->dataChecksumState),
     128              :                          (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
     129              :     }
     130           94 :     else if (info == XLOG_NEXTOID)
     131              :     {
     132              :         Oid         nextOid;
     133              : 
     134            1 :         memcpy(&nextOid, rec, sizeof(Oid));
     135            1 :         appendStringInfo(buf, "%u", nextOid);
     136              :     }
     137           93 :     else if (info == XLOG_RESTORE_POINT)
     138              :     {
     139            0 :         xl_restore_point *xlrec = (xl_restore_point *) rec;
     140              : 
     141            0 :         appendStringInfoString(buf, xlrec->rp_name);
     142              :     }
     143           93 :     else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
     144              :     {
     145              :         /* no further information to print */
     146              :     }
     147           48 :     else if (info == XLOG_BACKUP_END)
     148              :     {
     149              :         XLogRecPtr  startpoint;
     150              : 
     151           10 :         memcpy(&startpoint, rec, sizeof(XLogRecPtr));
     152           10 :         appendStringInfo(buf, "%X/%08X", LSN_FORMAT_ARGS(startpoint));
     153              :     }
     154           38 :     else if (info == XLOG_PARAMETER_CHANGE)
     155              :     {
     156              :         xl_parameter_change xlrec;
     157              :         const char *wal_level_str;
     158              : 
     159            3 :         memcpy(&xlrec, rec, sizeof(xl_parameter_change));
     160            3 :         wal_level_str = get_wal_level_string(xlrec.wal_level);
     161              : 
     162            6 :         appendStringInfo(buf, "max_connections=%d max_worker_processes=%d "
     163              :                          "max_wal_senders=%d max_prepared_xacts=%d "
     164              :                          "max_locks_per_xact=%d wal_level=%s "
     165              :                          "wal_log_hints=%s track_commit_timestamp=%s",
     166              :                          xlrec.MaxConnections,
     167              :                          xlrec.max_worker_processes,
     168              :                          xlrec.max_wal_senders,
     169              :                          xlrec.max_prepared_xacts,
     170              :                          xlrec.max_locks_per_xact,
     171              :                          wal_level_str,
     172            3 :                          xlrec.wal_log_hints ? "on" : "off",
     173            3 :                          xlrec.track_commit_timestamp ? "on" : "off");
     174              :     }
     175           35 :     else if (info == XLOG_FPW_CHANGE)
     176              :     {
     177              :         bool        fpw;
     178              : 
     179            0 :         memcpy(&fpw, rec, sizeof(bool));
     180            0 :         appendStringInfoString(buf, fpw ? "true" : "false");
     181              :     }
     182           35 :     else if (info == XLOG_END_OF_RECOVERY)
     183              :     {
     184              :         xl_end_of_recovery xlrec;
     185              : 
     186            0 :         memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
     187            0 :         appendStringInfo(buf, "tli %u; prev tli %u; time %s; wal_level %s",
     188              :                          xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
     189              :                          timestamptz_to_str(xlrec.end_time),
     190              :                          get_wal_level_string(xlrec.wal_level));
     191              :     }
     192           35 :     else if (info == XLOG_OVERWRITE_CONTRECORD)
     193              :     {
     194              :         xl_overwrite_contrecord xlrec;
     195              : 
     196            1 :         memcpy(&xlrec, rec, sizeof(xl_overwrite_contrecord));
     197            1 :         appendStringInfo(buf, "lsn %X/%08X; time %s",
     198            1 :                          LSN_FORMAT_ARGS(xlrec.overwritten_lsn),
     199              :                          timestamptz_to_str(xlrec.overwrite_time));
     200              :     }
     201           34 :     else if (info == XLOG_CHECKPOINT_REDO)
     202              :     {
     203              :         xl_checkpoint_redo xlrec;
     204              : 
     205            1 :         memcpy(&xlrec, rec, sizeof(xl_checkpoint_redo));
     206            1 :         appendStringInfo(buf, "wal_level %s; checksums %s",
     207              :                          get_wal_level_string(xlrec.wal_level),
     208              :                          get_checksum_state_string(xlrec.data_checksum_version));
     209              :     }
     210           33 :     else if (info == XLOG_LOGICAL_DECODING_STATUS_CHANGE)
     211              :     {
     212              :         bool        enabled;
     213              : 
     214           32 :         memcpy(&enabled, rec, sizeof(bool));
     215           32 :         appendStringInfoString(buf, enabled ? "true" : "false");
     216              :     }
     217              :     else if (info == XLOG_ASSIGN_LSN)
     218              :     {
     219              :         /* no further information to print */
     220              :     }
     221          101 : }
     222              : 
     223              : const char *
     224          101 : xlog_identify(uint8 info)
     225              : {
     226          101 :     const char *id = NULL;
     227              : 
     228          101 :     switch (info & ~XLR_INFO_MASK)
     229              :     {
     230            7 :         case XLOG_CHECKPOINT_SHUTDOWN:
     231            7 :             id = "CHECKPOINT_SHUTDOWN";
     232            7 :             break;
     233            0 :         case XLOG_CHECKPOINT_ONLINE:
     234            0 :             id = "CHECKPOINT_ONLINE";
     235            0 :             break;
     236            0 :         case XLOG_NOOP:
     237            0 :             id = "NOOP";
     238            0 :             break;
     239            1 :         case XLOG_NEXTOID:
     240            1 :             id = "NEXTOID";
     241            1 :             break;
     242            1 :         case XLOG_SWITCH:
     243            1 :             id = "SWITCH";
     244            1 :             break;
     245           10 :         case XLOG_BACKUP_END:
     246           10 :             id = "BACKUP_END";
     247           10 :             break;
     248            3 :         case XLOG_PARAMETER_CHANGE:
     249            3 :             id = "PARAMETER_CHANGE";
     250            3 :             break;
     251            0 :         case XLOG_RESTORE_POINT:
     252            0 :             id = "RESTORE_POINT";
     253            0 :             break;
     254            0 :         case XLOG_FPW_CHANGE:
     255            0 :             id = "FPW_CHANGE";
     256            0 :             break;
     257            0 :         case XLOG_END_OF_RECOVERY:
     258            0 :             id = "END_OF_RECOVERY";
     259            0 :             break;
     260            1 :         case XLOG_OVERWRITE_CONTRECORD:
     261            1 :             id = "OVERWRITE_CONTRECORD";
     262            1 :             break;
     263           27 :         case XLOG_FPI:
     264           27 :             id = "FPI";
     265           27 :             break;
     266           18 :         case XLOG_FPI_FOR_HINT:
     267           18 :             id = "FPI_FOR_HINT";
     268           18 :             break;
     269            1 :         case XLOG_CHECKPOINT_REDO:
     270            1 :             id = "CHECKPOINT_REDO";
     271            1 :             break;
     272           32 :         case XLOG_LOGICAL_DECODING_STATUS_CHANGE:
     273           32 :             id = "LOGICAL_DECODING_STATUS_CHANGE";
     274           32 :             break;
     275            0 :         case XLOG_ASSIGN_LSN:
     276            0 :             id = "ASSIGN_LSN";
     277            0 :             break;
     278              :     }
     279              : 
     280          101 :     return id;
     281              : }
     282              : 
     283              : const char *
     284            0 : xlog2_identify(uint8 info)
     285              : {
     286            0 :     const char *id = NULL;
     287              : 
     288            0 :     switch (info & ~XLR_INFO_MASK)
     289              :     {
     290            0 :         case XLOG2_CHECKSUMS:
     291            0 :             id = "CHECKSUMS";
     292            0 :             break;
     293              :     }
     294              : 
     295            0 :     return id;
     296              : }
     297              : 
     298              : /*
     299              :  * Returns a string giving information about all the blocks in an
     300              :  * XLogRecord.
     301              :  */
     302              : void
     303        34315 : XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty,
     304              :                        bool detailed_format, StringInfo buf,
     305              :                        uint32 *fpi_len)
     306              : {
     307              :     int         block_id;
     308              : 
     309              :     Assert(record != NULL);
     310              : 
     311        34315 :     if (detailed_format && pretty)
     312            0 :         appendStringInfoChar(buf, '\n');
     313              : 
     314        70641 :     for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
     315              :     {
     316              :         RelFileLocator rlocator;
     317              :         ForkNumber  forknum;
     318              :         BlockNumber blk;
     319              : 
     320        36326 :         if (!XLogRecGetBlockTagExtended(record, block_id,
     321              :                                         &rlocator, &forknum, &blk, NULL))
     322            3 :             continue;
     323              : 
     324        36323 :         if (detailed_format)
     325              :         {
     326              :             /* Get block references in detailed format. */
     327              : 
     328        36323 :             if (pretty)
     329            0 :                 appendStringInfoChar(buf, '\t');
     330        36323 :             else if (block_id > 0)
     331         2008 :                 appendStringInfoChar(buf, ' ');
     332              : 
     333        36323 :             appendStringInfo(buf,
     334              :                              "blkref #%d: rel %u/%u/%u fork %s blk %u",
     335              :                              block_id,
     336              :                              rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
     337        36323 :                              forkNames[forknum],
     338              :                              blk);
     339              : 
     340        36323 :             if (XLogRecHasBlockImage(record, block_id))
     341              :             {
     342         5262 :                 uint8       bimg_info = XLogRecGetBlock(record, block_id)->bimg_info;
     343              : 
     344              :                 /* Calculate the amount of FPI data in the record. */
     345         5262 :                 if (fpi_len)
     346         5262 :                     *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
     347              : 
     348         5262 :                 if (BKPIMAGE_COMPRESSED(bimg_info))
     349              :                 {
     350              :                     const char *method;
     351              : 
     352            0 :                     if ((bimg_info & BKPIMAGE_COMPRESS_PGLZ) != 0)
     353            0 :                         method = "pglz";
     354            0 :                     else if ((bimg_info & BKPIMAGE_COMPRESS_LZ4) != 0)
     355            0 :                         method = "lz4";
     356            0 :                     else if ((bimg_info & BKPIMAGE_COMPRESS_ZSTD) != 0)
     357            0 :                         method = "zstd";
     358              :                     else
     359            0 :                         method = "unknown";
     360              : 
     361            0 :                     appendStringInfo(buf,
     362              :                                      " (FPW%s); hole: offset: %u, length: %u, "
     363              :                                      "compression saved: %u, method: %s",
     364            0 :                                      XLogRecBlockImageApply(record, block_id) ?
     365              :                                      "" : " for WAL verification",
     366            0 :                                      XLogRecGetBlock(record, block_id)->hole_offset,
     367            0 :                                      XLogRecGetBlock(record, block_id)->hole_length,
     368              :                                      BLCKSZ -
     369            0 :                                      XLogRecGetBlock(record, block_id)->hole_length -
     370            0 :                                      XLogRecGetBlock(record, block_id)->bimg_len,
     371              :                                      method);
     372              :                 }
     373              :                 else
     374              :                 {
     375         5262 :                     appendStringInfo(buf,
     376              :                                      " (FPW%s); hole: offset: %u, length: %u",
     377         5262 :                                      XLogRecBlockImageApply(record, block_id) ?
     378              :                                      "" : " for WAL verification",
     379         5262 :                                      XLogRecGetBlock(record, block_id)->hole_offset,
     380         5262 :                                      XLogRecGetBlock(record, block_id)->hole_length);
     381              :                 }
     382              :             }
     383              : 
     384        36323 :             if (pretty)
     385            0 :                 appendStringInfoChar(buf, '\n');
     386              :         }
     387              :         else
     388              :         {
     389              :             /* Get block references in short format. */
     390              : 
     391            0 :             if (forknum != MAIN_FORKNUM)
     392              :             {
     393            0 :                 appendStringInfo(buf,
     394              :                                  ", blkref #%d: rel %u/%u/%u fork %s blk %u",
     395              :                                  block_id,
     396              :                                  rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
     397            0 :                                  forkNames[forknum],
     398              :                                  blk);
     399              :             }
     400              :             else
     401              :             {
     402            0 :                 appendStringInfo(buf,
     403              :                                  ", blkref #%d: rel %u/%u/%u blk %u",
     404              :                                  block_id,
     405              :                                  rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
     406              :                                  blk);
     407              :             }
     408              : 
     409            0 :             if (XLogRecHasBlockImage(record, block_id))
     410              :             {
     411              :                 /* Calculate the amount of FPI data in the record. */
     412            0 :                 if (fpi_len)
     413            0 :                     *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
     414              : 
     415            0 :                 if (XLogRecBlockImageApply(record, block_id))
     416            0 :                     appendStringInfoString(buf, " FPW");
     417              :                 else
     418            0 :                     appendStringInfoString(buf, " FPW for WAL verification");
     419              :             }
     420              :         }
     421              :     }
     422              : 
     423        34315 :     if (!detailed_format && pretty)
     424            0 :         appendStringInfoChar(buf, '\n');
     425        34315 : }
        

Generated by: LCOV version 2.0-1