LCOV - code coverage report
Current view: top level - src/bin/pg_waldump - xlogdesc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 89 151 58.9 %
Date: 2025-12-26 19:18:48 Functions: 4 4 100.0 %
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-2025, 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 "utils/guc.h"
      22             : #include "utils/timestamp.h"
      23             : 
      24             : /*
      25             :  * GUC support
      26             :  */
      27             : const struct config_enum_entry wal_level_options[] = {
      28             :     {"minimal", WAL_LEVEL_MINIMAL, false},
      29             :     {"replica", WAL_LEVEL_REPLICA, false},
      30             :     {"archive", WAL_LEVEL_REPLICA, true}, /* deprecated */
      31             :     {"hot_standby", WAL_LEVEL_REPLICA, true}, /* deprecated */
      32             :     {"logical", WAL_LEVEL_LOGICAL, false},
      33             :     {NULL, 0, false}
      34             : };
      35             : 
      36             : /*
      37             :  * Find a string representation for wal_level
      38             :  */
      39             : static const char *
      40          74 : get_wal_level_string(int wal_level)
      41             : {
      42             :     const struct config_enum_entry *entry;
      43          74 :     const char *wal_level_str = "?";
      44             : 
      45         238 :     for (entry = wal_level_options; entry->name; entry++)
      46             :     {
      47         238 :         if (entry->val == wal_level)
      48             :         {
      49          74 :             wal_level_str = entry->name;
      50          74 :             break;
      51             :         }
      52             :     }
      53             : 
      54          74 :     return wal_level_str;
      55             : }
      56             : 
      57             : void
      58       15504 : xlog_desc(StringInfo buf, XLogReaderState *record)
      59             : {
      60       15504 :     char       *rec = XLogRecGetData(record);
      61       15504 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
      62             : 
      63       15504 :     if (info == XLOG_CHECKPOINT_SHUTDOWN ||
      64             :         info == XLOG_CHECKPOINT_ONLINE)
      65          42 :     {
      66          42 :         CheckPoint *checkpoint = (CheckPoint *) rec;
      67             : 
      68         126 :         appendStringInfo(buf, "redo %X/%08X; "
      69             :                          "tli %u; prev tli %u; fpw %s; wal_level %s; logical decoding %s; xid %u:%u; oid %u; multi %u; offset %" PRIu64 "; "
      70             :                          "oldest xid %u in DB %u; oldest multi %u in DB %u; "
      71             :                          "oldest/newest commit timestamp xid: %u/%u; "
      72             :                          "oldest running xid %u; %s",
      73          42 :                          LSN_FORMAT_ARGS(checkpoint->redo),
      74             :                          checkpoint->ThisTimeLineID,
      75             :                          checkpoint->PrevTimeLineID,
      76          42 :                          checkpoint->fullPageWrites ? "true" : "false",
      77             :                          get_wal_level_string(checkpoint->wal_level),
      78          42 :                          checkpoint->logicalDecodingEnabled ? "true" : "false",
      79          42 :                          EpochFromFullTransactionId(checkpoint->nextXid),
      80          42 :                          XidFromFullTransactionId(checkpoint->nextXid),
      81             :                          checkpoint->nextOid,
      82             :                          checkpoint->nextMulti,
      83             :                          checkpoint->nextMultiOffset,
      84             :                          checkpoint->oldestXid,
      85             :                          checkpoint->oldestXidDB,
      86             :                          checkpoint->oldestMulti,
      87             :                          checkpoint->oldestMultiDB,
      88             :                          checkpoint->oldestCommitTsXid,
      89             :                          checkpoint->newestCommitTsXid,
      90             :                          checkpoint->oldestActiveXid,
      91             :                          (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
      92             :     }
      93       15462 :     else if (info == XLOG_NEXTOID)
      94             :     {
      95             :         Oid         nextOid;
      96             : 
      97          24 :         memcpy(&nextOid, rec, sizeof(Oid));
      98          24 :         appendStringInfo(buf, "%u", nextOid);
      99             :     }
     100       15438 :     else if (info == XLOG_RESTORE_POINT)
     101             :     {
     102           0 :         xl_restore_point *xlrec = (xl_restore_point *) rec;
     103             : 
     104           0 :         appendStringInfoString(buf, xlrec->rp_name);
     105             :     }
     106       15438 :     else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
     107             :     {
     108             :         /* no further information to print */
     109             :     }
     110          44 :     else if (info == XLOG_BACKUP_END)
     111             :     {
     112             :         XLogRecPtr  startpoint;
     113             : 
     114           0 :         memcpy(&startpoint, rec, sizeof(XLogRecPtr));
     115           0 :         appendStringInfo(buf, "%X/%08X", LSN_FORMAT_ARGS(startpoint));
     116             :     }
     117          44 :     else if (info == XLOG_PARAMETER_CHANGE)
     118             :     {
     119             :         xl_parameter_change xlrec;
     120             :         const char *wal_level_str;
     121             : 
     122           4 :         memcpy(&xlrec, rec, sizeof(xl_parameter_change));
     123           4 :         wal_level_str = get_wal_level_string(xlrec.wal_level);
     124             : 
     125           8 :         appendStringInfo(buf, "max_connections=%d max_worker_processes=%d "
     126             :                          "max_wal_senders=%d max_prepared_xacts=%d "
     127             :                          "max_locks_per_xact=%d wal_level=%s "
     128             :                          "wal_log_hints=%s track_commit_timestamp=%s",
     129             :                          xlrec.MaxConnections,
     130             :                          xlrec.max_worker_processes,
     131             :                          xlrec.max_wal_senders,
     132             :                          xlrec.max_prepared_xacts,
     133             :                          xlrec.max_locks_per_xact,
     134             :                          wal_level_str,
     135           4 :                          xlrec.wal_log_hints ? "on" : "off",
     136           4 :                          xlrec.track_commit_timestamp ? "on" : "off");
     137             :     }
     138          40 :     else if (info == XLOG_FPW_CHANGE)
     139             :     {
     140             :         bool        fpw;
     141             : 
     142           0 :         memcpy(&fpw, rec, sizeof(bool));
     143           0 :         appendStringInfoString(buf, fpw ? "true" : "false");
     144             :     }
     145          40 :     else if (info == XLOG_END_OF_RECOVERY)
     146             :     {
     147             :         xl_end_of_recovery xlrec;
     148             : 
     149           0 :         memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
     150           0 :         appendStringInfo(buf, "tli %u; prev tli %u; time %s; wal_level %s",
     151             :                          xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
     152             :                          timestamptz_to_str(xlrec.end_time),
     153             :                          get_wal_level_string(xlrec.wal_level));
     154             :     }
     155          40 :     else if (info == XLOG_OVERWRITE_CONTRECORD)
     156             :     {
     157             :         xl_overwrite_contrecord xlrec;
     158             : 
     159           0 :         memcpy(&xlrec, rec, sizeof(xl_overwrite_contrecord));
     160           0 :         appendStringInfo(buf, "lsn %X/%08X; time %s",
     161           0 :                          LSN_FORMAT_ARGS(xlrec.overwritten_lsn),
     162             :                          timestamptz_to_str(xlrec.overwrite_time));
     163             :     }
     164          40 :     else if (info == XLOG_CHECKPOINT_REDO)
     165             :     {
     166             :         int         wal_level;
     167             : 
     168          28 :         memcpy(&wal_level, rec, sizeof(int));
     169          28 :         appendStringInfo(buf, "wal_level %s", get_wal_level_string(wal_level));
     170             :     }
     171          12 :     else if (info == XLOG_LOGICAL_DECODING_STATUS_CHANGE)
     172             :     {
     173             :         bool        enabled;
     174             : 
     175           4 :         memcpy(&enabled, rec, sizeof(bool));
     176           4 :         appendStringInfoString(buf, enabled ? "true" : "false");
     177             :     }
     178       15504 : }
     179             : 
     180             : const char *
     181       15514 : xlog_identify(uint8 info)
     182             : {
     183       15514 :     const char *id = NULL;
     184             : 
     185       15514 :     switch (info & ~XLR_INFO_MASK)
     186             :     {
     187          14 :         case XLOG_CHECKPOINT_SHUTDOWN:
     188          14 :             id = "CHECKPOINT_SHUTDOWN";
     189          14 :             break;
     190          30 :         case XLOG_CHECKPOINT_ONLINE:
     191          30 :             id = "CHECKPOINT_ONLINE";
     192          30 :             break;
     193           0 :         case XLOG_NOOP:
     194           0 :             id = "NOOP";
     195           0 :             break;
     196          26 :         case XLOG_NEXTOID:
     197          26 :             id = "NEXTOID";
     198          26 :             break;
     199           8 :         case XLOG_SWITCH:
     200           8 :             id = "SWITCH";
     201           8 :             break;
     202           0 :         case XLOG_BACKUP_END:
     203           0 :             id = "BACKUP_END";
     204           0 :             break;
     205           4 :         case XLOG_PARAMETER_CHANGE:
     206           4 :             id = "PARAMETER_CHANGE";
     207           4 :             break;
     208           0 :         case XLOG_RESTORE_POINT:
     209           0 :             id = "RESTORE_POINT";
     210           0 :             break;
     211           0 :         case XLOG_FPW_CHANGE:
     212           0 :             id = "FPW_CHANGE";
     213           0 :             break;
     214           0 :         case XLOG_END_OF_RECOVERY:
     215           0 :             id = "END_OF_RECOVERY";
     216           0 :             break;
     217           0 :         case XLOG_OVERWRITE_CONTRECORD:
     218           0 :             id = "OVERWRITE_CONTRECORD";
     219           0 :             break;
     220       14128 :         case XLOG_FPI:
     221       14128 :             id = "FPI";
     222       14128 :             break;
     223        1270 :         case XLOG_FPI_FOR_HINT:
     224        1270 :             id = "FPI_FOR_HINT";
     225        1270 :             break;
     226          30 :         case XLOG_CHECKPOINT_REDO:
     227          30 :             id = "CHECKPOINT_REDO";
     228          30 :             break;
     229           4 :         case XLOG_LOGICAL_DECODING_STATUS_CHANGE:
     230           4 :             id = "LOGICAL_DECODING_STATUS_CHANGE";
     231           4 :             break;
     232             :     }
     233             : 
     234       15514 :     return id;
     235             : }
     236             : 
     237             : /*
     238             :  * Returns a string giving information about all the blocks in an
     239             :  * XLogRecord.
     240             :  */
     241             : void
     242      515736 : XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty,
     243             :                        bool detailed_format, StringInfo buf,
     244             :                        uint32 *fpi_len)
     245             : {
     246             :     int         block_id;
     247             : 
     248             :     Assert(record != NULL);
     249             : 
     250      515736 :     if (detailed_format && pretty)
     251           0 :         appendStringInfoChar(buf, '\n');
     252             : 
     253     1086976 :     for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
     254             :     {
     255             :         RelFileLocator rlocator;
     256             :         ForkNumber  forknum;
     257             :         BlockNumber blk;
     258             : 
     259      571240 :         if (!XLogRecGetBlockTagExtended(record, block_id,
     260             :                                         &rlocator, &forknum, &blk, NULL))
     261         178 :             continue;
     262             : 
     263      571062 :         if (detailed_format)
     264             :         {
     265             :             /* Get block references in detailed format. */
     266             : 
     267           0 :             if (pretty)
     268           0 :                 appendStringInfoChar(buf, '\t');
     269           0 :             else if (block_id > 0)
     270           0 :                 appendStringInfoChar(buf, ' ');
     271             : 
     272           0 :             appendStringInfo(buf,
     273             :                              "blkref #%d: rel %u/%u/%u fork %s blk %u",
     274             :                              block_id,
     275             :                              rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
     276           0 :                              forkNames[forknum],
     277             :                              blk);
     278             : 
     279           0 :             if (XLogRecHasBlockImage(record, block_id))
     280             :             {
     281           0 :                 uint8       bimg_info = XLogRecGetBlock(record, block_id)->bimg_info;
     282             : 
     283             :                 /* Calculate the amount of FPI data in the record. */
     284           0 :                 if (fpi_len)
     285           0 :                     *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
     286             : 
     287           0 :                 if (BKPIMAGE_COMPRESSED(bimg_info))
     288             :                 {
     289             :                     const char *method;
     290             : 
     291           0 :                     if ((bimg_info & BKPIMAGE_COMPRESS_PGLZ) != 0)
     292           0 :                         method = "pglz";
     293           0 :                     else if ((bimg_info & BKPIMAGE_COMPRESS_LZ4) != 0)
     294           0 :                         method = "lz4";
     295           0 :                     else if ((bimg_info & BKPIMAGE_COMPRESS_ZSTD) != 0)
     296           0 :                         method = "zstd";
     297             :                     else
     298           0 :                         method = "unknown";
     299             : 
     300           0 :                     appendStringInfo(buf,
     301             :                                      " (FPW%s); hole: offset: %u, length: %u, "
     302             :                                      "compression saved: %u, method: %s",
     303           0 :                                      XLogRecBlockImageApply(record, block_id) ?
     304             :                                      "" : " for WAL verification",
     305           0 :                                      XLogRecGetBlock(record, block_id)->hole_offset,
     306           0 :                                      XLogRecGetBlock(record, block_id)->hole_length,
     307             :                                      BLCKSZ -
     308           0 :                                      XLogRecGetBlock(record, block_id)->hole_length -
     309           0 :                                      XLogRecGetBlock(record, block_id)->bimg_len,
     310             :                                      method);
     311             :                 }
     312             :                 else
     313             :                 {
     314           0 :                     appendStringInfo(buf,
     315             :                                      " (FPW%s); hole: offset: %u, length: %u",
     316           0 :                                      XLogRecBlockImageApply(record, block_id) ?
     317             :                                      "" : " for WAL verification",
     318           0 :                                      XLogRecGetBlock(record, block_id)->hole_offset,
     319           0 :                                      XLogRecGetBlock(record, block_id)->hole_length);
     320             :                 }
     321             :             }
     322             : 
     323           0 :             if (pretty)
     324           0 :                 appendStringInfoChar(buf, '\n');
     325             :         }
     326             :         else
     327             :         {
     328             :             /* Get block references in short format. */
     329             : 
     330      571062 :             if (forknum != MAIN_FORKNUM)
     331             :             {
     332        6452 :                 appendStringInfo(buf,
     333             :                                  ", blkref #%d: rel %u/%u/%u fork %s blk %u",
     334             :                                  block_id,
     335             :                                  rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
     336        6452 :                                  forkNames[forknum],
     337             :                                  blk);
     338             :             }
     339             :             else
     340             :             {
     341      564610 :                 appendStringInfo(buf,
     342             :                                  ", blkref #%d: rel %u/%u/%u blk %u",
     343             :                                  block_id,
     344             :                                  rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
     345             :                                  blk);
     346             :             }
     347             : 
     348      571062 :             if (XLogRecHasBlockImage(record, block_id))
     349             :             {
     350             :                 /* Calculate the amount of FPI data in the record. */
     351       18408 :                 if (fpi_len)
     352           0 :                     *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
     353             : 
     354       18408 :                 if (XLogRecBlockImageApply(record, block_id))
     355       18408 :                     appendStringInfoString(buf, " FPW");
     356             :                 else
     357           0 :                     appendStringInfoString(buf, " FPW for WAL verification");
     358             :             }
     359             :         }
     360             :     }
     361             : 
     362      515736 :     if (!detailed_format && pretty)
     363      515736 :         appendStringInfoChar(buf, '\n');
     364      515736 : }

Generated by: LCOV version 1.16