LCOV - code coverage report
Current view: top level - src/bin/pg_waldump - xlogdesc.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 57.8 % 154 89
Test Date: 2026-03-14 12:15:02 Functions: 100.0 % 4 4
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 "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           37 : get_wal_level_string(int wal_level)
      41              : {
      42              :     const struct config_enum_entry *entry;
      43           37 :     const char *wal_level_str = "?";
      44              : 
      45          119 :     for (entry = wal_level_options; entry->name; entry++)
      46              :     {
      47          119 :         if (entry->val == wal_level)
      48              :         {
      49           37 :             wal_level_str = entry->name;
      50           37 :             break;
      51              :         }
      52              :     }
      53              : 
      54           37 :     return wal_level_str;
      55              : }
      56              : 
      57              : void
      58         7703 : xlog_desc(StringInfo buf, XLogReaderState *record)
      59              : {
      60         7703 :     char       *rec = XLogRecGetData(record);
      61         7703 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
      62              : 
      63         7703 :     if (info == XLOG_CHECKPOINT_SHUTDOWN ||
      64              :         info == XLOG_CHECKPOINT_ONLINE)
      65           21 :     {
      66           21 :         CheckPoint *checkpoint = (CheckPoint *) rec;
      67              : 
      68           63 :         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           21 :                          LSN_FORMAT_ARGS(checkpoint->redo),
      74              :                          checkpoint->ThisTimeLineID,
      75              :                          checkpoint->PrevTimeLineID,
      76           21 :                          checkpoint->fullPageWrites ? "true" : "false",
      77              :                          get_wal_level_string(checkpoint->wal_level),
      78           21 :                          checkpoint->logicalDecodingEnabled ? "true" : "false",
      79           21 :                          EpochFromFullTransactionId(checkpoint->nextXid),
      80           21 :                          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         7682 :     else if (info == XLOG_NEXTOID)
      94              :     {
      95              :         Oid         nextOid;
      96              : 
      97           12 :         memcpy(&nextOid, rec, sizeof(Oid));
      98           12 :         appendStringInfo(buf, "%u", nextOid);
      99              :     }
     100         7670 :     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         7670 :     else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
     107              :     {
     108              :         /* no further information to print */
     109              :     }
     110           22 :     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           22 :     else if (info == XLOG_PARAMETER_CHANGE)
     118              :     {
     119              :         xl_parameter_change xlrec;
     120              :         const char *wal_level_str;
     121              : 
     122            2 :         memcpy(&xlrec, rec, sizeof(xl_parameter_change));
     123            2 :         wal_level_str = get_wal_level_string(xlrec.wal_level);
     124              : 
     125            4 :         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            2 :                          xlrec.wal_log_hints ? "on" : "off",
     136            2 :                          xlrec.track_commit_timestamp ? "on" : "off");
     137              :     }
     138           20 :     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           20 :     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           20 :     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           20 :     else if (info == XLOG_CHECKPOINT_REDO)
     165              :     {
     166              :         int         wal_level;
     167              : 
     168           14 :         memcpy(&wal_level, rec, sizeof(int));
     169           14 :         appendStringInfo(buf, "wal_level %s", get_wal_level_string(wal_level));
     170              :     }
     171            6 :     else if (info == XLOG_LOGICAL_DECODING_STATUS_CHANGE)
     172              :     {
     173              :         bool        enabled;
     174              : 
     175            2 :         memcpy(&enabled, rec, sizeof(bool));
     176            2 :         appendStringInfoString(buf, enabled ? "true" : "false");
     177              :     }
     178              :     else if (info == XLOG_ASSIGN_LSN)
     179              :     {
     180              :         /* no further information to print */
     181              :     }
     182         7703 : }
     183              : 
     184              : const char *
     185         7708 : xlog_identify(uint8 info)
     186              : {
     187         7708 :     const char *id = NULL;
     188              : 
     189         7708 :     switch (info & ~XLR_INFO_MASK)
     190              :     {
     191            7 :         case XLOG_CHECKPOINT_SHUTDOWN:
     192            7 :             id = "CHECKPOINT_SHUTDOWN";
     193            7 :             break;
     194           15 :         case XLOG_CHECKPOINT_ONLINE:
     195           15 :             id = "CHECKPOINT_ONLINE";
     196           15 :             break;
     197            0 :         case XLOG_NOOP:
     198            0 :             id = "NOOP";
     199            0 :             break;
     200           13 :         case XLOG_NEXTOID:
     201           13 :             id = "NEXTOID";
     202           13 :             break;
     203            4 :         case XLOG_SWITCH:
     204            4 :             id = "SWITCH";
     205            4 :             break;
     206            0 :         case XLOG_BACKUP_END:
     207            0 :             id = "BACKUP_END";
     208            0 :             break;
     209            2 :         case XLOG_PARAMETER_CHANGE:
     210            2 :             id = "PARAMETER_CHANGE";
     211            2 :             break;
     212            0 :         case XLOG_RESTORE_POINT:
     213            0 :             id = "RESTORE_POINT";
     214            0 :             break;
     215            0 :         case XLOG_FPW_CHANGE:
     216            0 :             id = "FPW_CHANGE";
     217            0 :             break;
     218            0 :         case XLOG_END_OF_RECOVERY:
     219            0 :             id = "END_OF_RECOVERY";
     220            0 :             break;
     221            0 :         case XLOG_OVERWRITE_CONTRECORD:
     222            0 :             id = "OVERWRITE_CONTRECORD";
     223            0 :             break;
     224         7015 :         case XLOG_FPI:
     225         7015 :             id = "FPI";
     226         7015 :             break;
     227          635 :         case XLOG_FPI_FOR_HINT:
     228          635 :             id = "FPI_FOR_HINT";
     229          635 :             break;
     230           15 :         case XLOG_CHECKPOINT_REDO:
     231           15 :             id = "CHECKPOINT_REDO";
     232           15 :             break;
     233            2 :         case XLOG_LOGICAL_DECODING_STATUS_CHANGE:
     234            2 :             id = "LOGICAL_DECODING_STATUS_CHANGE";
     235            2 :             break;
     236            0 :         case XLOG_ASSIGN_LSN:
     237            0 :             id = "ASSIGN_LSN";
     238            0 :             break;
     239              :     }
     240              : 
     241         7708 :     return id;
     242              : }
     243              : 
     244              : /*
     245              :  * Returns a string giving information about all the blocks in an
     246              :  * XLogRecord.
     247              :  */
     248              : void
     249       257869 : XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty,
     250              :                        bool detailed_format, StringInfo buf,
     251              :                        uint32 *fpi_len)
     252              : {
     253              :     int         block_id;
     254              : 
     255              :     Assert(record != NULL);
     256              : 
     257       257869 :     if (detailed_format && pretty)
     258            0 :         appendStringInfoChar(buf, '\n');
     259              : 
     260       543583 :     for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
     261              :     {
     262              :         RelFileLocator rlocator;
     263              :         ForkNumber  forknum;
     264              :         BlockNumber blk;
     265              : 
     266       285714 :         if (!XLogRecGetBlockTagExtended(record, block_id,
     267              :                                         &rlocator, &forknum, &blk, NULL))
     268           81 :             continue;
     269              : 
     270       285633 :         if (detailed_format)
     271              :         {
     272              :             /* Get block references in detailed format. */
     273              : 
     274            0 :             if (pretty)
     275            0 :                 appendStringInfoChar(buf, '\t');
     276            0 :             else if (block_id > 0)
     277            0 :                 appendStringInfoChar(buf, ' ');
     278              : 
     279            0 :             appendStringInfo(buf,
     280              :                              "blkref #%d: rel %u/%u/%u fork %s blk %u",
     281              :                              block_id,
     282              :                              rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
     283            0 :                              forkNames[forknum],
     284              :                              blk);
     285              : 
     286            0 :             if (XLogRecHasBlockImage(record, block_id))
     287              :             {
     288            0 :                 uint8       bimg_info = XLogRecGetBlock(record, block_id)->bimg_info;
     289              : 
     290              :                 /* Calculate the amount of FPI data in the record. */
     291            0 :                 if (fpi_len)
     292            0 :                     *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
     293              : 
     294            0 :                 if (BKPIMAGE_COMPRESSED(bimg_info))
     295              :                 {
     296              :                     const char *method;
     297              : 
     298            0 :                     if ((bimg_info & BKPIMAGE_COMPRESS_PGLZ) != 0)
     299            0 :                         method = "pglz";
     300            0 :                     else if ((bimg_info & BKPIMAGE_COMPRESS_LZ4) != 0)
     301            0 :                         method = "lz4";
     302            0 :                     else if ((bimg_info & BKPIMAGE_COMPRESS_ZSTD) != 0)
     303            0 :                         method = "zstd";
     304              :                     else
     305            0 :                         method = "unknown";
     306              : 
     307            0 :                     appendStringInfo(buf,
     308              :                                      " (FPW%s); hole: offset: %u, length: %u, "
     309              :                                      "compression saved: %u, method: %s",
     310            0 :                                      XLogRecBlockImageApply(record, block_id) ?
     311              :                                      "" : " for WAL verification",
     312            0 :                                      XLogRecGetBlock(record, block_id)->hole_offset,
     313            0 :                                      XLogRecGetBlock(record, block_id)->hole_length,
     314              :                                      BLCKSZ -
     315            0 :                                      XLogRecGetBlock(record, block_id)->hole_length -
     316            0 :                                      XLogRecGetBlock(record, block_id)->bimg_len,
     317              :                                      method);
     318              :                 }
     319              :                 else
     320              :                 {
     321            0 :                     appendStringInfo(buf,
     322              :                                      " (FPW%s); hole: offset: %u, length: %u",
     323            0 :                                      XLogRecBlockImageApply(record, block_id) ?
     324              :                                      "" : " for WAL verification",
     325            0 :                                      XLogRecGetBlock(record, block_id)->hole_offset,
     326            0 :                                      XLogRecGetBlock(record, block_id)->hole_length);
     327              :                 }
     328              :             }
     329              : 
     330            0 :             if (pretty)
     331            0 :                 appendStringInfoChar(buf, '\n');
     332              :         }
     333              :         else
     334              :         {
     335              :             /* Get block references in short format. */
     336              : 
     337       285633 :             if (forknum != MAIN_FORKNUM)
     338              :             {
     339         3212 :                 appendStringInfo(buf,
     340              :                                  ", blkref #%d: rel %u/%u/%u fork %s blk %u",
     341              :                                  block_id,
     342              :                                  rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
     343         3212 :                                  forkNames[forknum],
     344              :                                  blk);
     345              :             }
     346              :             else
     347              :             {
     348       282421 :                 appendStringInfo(buf,
     349              :                                  ", blkref #%d: rel %u/%u/%u blk %u",
     350              :                                  block_id,
     351              :                                  rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
     352              :                                  blk);
     353              :             }
     354              : 
     355       285633 :             if (XLogRecHasBlockImage(record, block_id))
     356              :             {
     357              :                 /* Calculate the amount of FPI data in the record. */
     358         9165 :                 if (fpi_len)
     359            0 :                     *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
     360              : 
     361         9165 :                 if (XLogRecBlockImageApply(record, block_id))
     362         9165 :                     appendStringInfoString(buf, " FPW");
     363              :                 else
     364            0 :                     appendStringInfoString(buf, " FPW for WAL verification");
     365              :             }
     366              :         }
     367              :     }
     368              : 
     369       257869 :     if (!detailed_format && pretty)
     370       257869 :         appendStringInfoChar(buf, '\n');
     371       257869 : }
        

Generated by: LCOV version 2.0-1