LCOV - code coverage report
Current view: top level - src/bin/pg_waldump - nbtdesc.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 68.4 % 136 93
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 3 3
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * nbtdesc.c
       4              :  *    rmgr descriptor routines for access/nbtree/nbtxlog.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/nbtdesc.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #include "postgres.h"
      16              : 
      17              : #include "access/nbtxlog.h"
      18              : #include "access/rmgrdesc_utils.h"
      19              : 
      20              : static void delvacuum_desc(StringInfo buf, char *block_data,
      21              :                            uint16 ndeleted, uint16 nupdated);
      22              : 
      23              : void
      24        37262 : btree_desc(StringInfo buf, XLogReaderState *record)
      25              : {
      26        37262 :     char       *rec = XLogRecGetData(record);
      27        37262 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
      28              : 
      29        37262 :     switch (info)
      30              :     {
      31        36790 :         case XLOG_BTREE_INSERT_LEAF:
      32              :         case XLOG_BTREE_INSERT_UPPER:
      33              :         case XLOG_BTREE_INSERT_META:
      34              :         case XLOG_BTREE_INSERT_POST:
      35              :             {
      36        36790 :                 xl_btree_insert *xlrec = (xl_btree_insert *) rec;
      37              : 
      38        36790 :                 appendStringInfo(buf, "off: %u", xlrec->offnum);
      39        36790 :                 break;
      40              :             }
      41          118 :         case XLOG_BTREE_SPLIT_L:
      42              :         case XLOG_BTREE_SPLIT_R:
      43              :             {
      44          118 :                 xl_btree_split *xlrec = (xl_btree_split *) rec;
      45              : 
      46          118 :                 appendStringInfo(buf, "level: %u, firstrightoff: %d, newitemoff: %d, postingoff: %d",
      47          118 :                                  xlrec->level, xlrec->firstrightoff,
      48          118 :                                  xlrec->newitemoff, xlrec->postingoff);
      49          118 :                 break;
      50              :             }
      51           98 :         case XLOG_BTREE_DEDUP:
      52              :             {
      53           98 :                 xl_btree_dedup *xlrec = (xl_btree_dedup *) rec;
      54              : 
      55           98 :                 appendStringInfo(buf, "nintervals: %u", xlrec->nintervals);
      56           98 :                 break;
      57              :             }
      58          132 :         case XLOG_BTREE_VACUUM:
      59              :             {
      60          132 :                 xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
      61              : 
      62          132 :                 appendStringInfo(buf, "ndeleted: %u, nupdated: %u",
      63          132 :                                  xlrec->ndeleted, xlrec->nupdated);
      64              : 
      65          132 :                 if (XLogRecHasBlockData(record, 0))
      66          132 :                     delvacuum_desc(buf, XLogRecGetBlockData(record, 0, NULL),
      67          132 :                                    xlrec->ndeleted, xlrec->nupdated);
      68          132 :                 break;
      69              :             }
      70           14 :         case XLOG_BTREE_DELETE:
      71              :             {
      72           14 :                 xl_btree_delete *xlrec = (xl_btree_delete *) rec;
      73              : 
      74           14 :                 appendStringInfo(buf, "snapshotConflictHorizon: %u, ndeleted: %u, nupdated: %u, isCatalogRel: %c",
      75              :                                  xlrec->snapshotConflictHorizon,
      76           14 :                                  xlrec->ndeleted, xlrec->nupdated,
      77           14 :                                  xlrec->isCatalogRel ? 'T' : 'F');
      78              : 
      79           14 :                 if (XLogRecHasBlockData(record, 0))
      80           14 :                     delvacuum_desc(buf, XLogRecGetBlockData(record, 0, NULL),
      81           14 :                                    xlrec->ndeleted, xlrec->nupdated);
      82           14 :                 break;
      83              :             }
      84            0 :         case XLOG_BTREE_MARK_PAGE_HALFDEAD:
      85              :             {
      86            0 :                 xl_btree_mark_page_halfdead *xlrec = (xl_btree_mark_page_halfdead *) rec;
      87              : 
      88            0 :                 appendStringInfo(buf, "topparent: %u, leaf: %u, left: %u, right: %u",
      89              :                                  xlrec->topparent, xlrec->leafblk, xlrec->leftblk, xlrec->rightblk);
      90            0 :                 break;
      91              :             }
      92            0 :         case XLOG_BTREE_UNLINK_PAGE_META:
      93              :         case XLOG_BTREE_UNLINK_PAGE:
      94              :             {
      95            0 :                 xl_btree_unlink_page *xlrec = (xl_btree_unlink_page *) rec;
      96              : 
      97            0 :                 appendStringInfo(buf, "left: %u, right: %u, level: %u, safexid: %u:%u, ",
      98              :                                  xlrec->leftsib, xlrec->rightsib, xlrec->level,
      99            0 :                                  EpochFromFullTransactionId(xlrec->safexid),
     100            0 :                                  XidFromFullTransactionId(xlrec->safexid));
     101            0 :                 appendStringInfo(buf, "leafleft: %u, leafright: %u, leaftopparent: %u",
     102              :                                  xlrec->leafleftsib, xlrec->leafrightsib,
     103              :                                  xlrec->leaftopparent);
     104            0 :                 break;
     105              :             }
     106          110 :         case XLOG_BTREE_NEWROOT:
     107              :             {
     108          110 :                 xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
     109              : 
     110          110 :                 appendStringInfo(buf, "level: %u", xlrec->level);
     111          110 :                 break;
     112              :             }
     113            0 :         case XLOG_BTREE_REUSE_PAGE:
     114              :             {
     115            0 :                 xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
     116              : 
     117            0 :                 appendStringInfo(buf, "rel: %u/%u/%u, snapshotConflictHorizon: %u:%u, isCatalogRel: %c",
     118              :                                  xlrec->locator.spcOid, xlrec->locator.dbOid,
     119              :                                  xlrec->locator.relNumber,
     120            0 :                                  EpochFromFullTransactionId(xlrec->snapshotConflictHorizon),
     121            0 :                                  XidFromFullTransactionId(xlrec->snapshotConflictHorizon),
     122            0 :                                  xlrec->isCatalogRel ? 'T' : 'F');
     123            0 :                 break;
     124              :             }
     125            0 :         case XLOG_BTREE_META_CLEANUP:
     126              :             {
     127              :                 xl_btree_metadata *xlrec;
     128              : 
     129            0 :                 xlrec = (xl_btree_metadata *) XLogRecGetBlockData(record, 0,
     130              :                                                                   NULL);
     131            0 :                 appendStringInfo(buf, "last_cleanup_num_delpages: %u",
     132              :                                  xlrec->last_cleanup_num_delpages);
     133            0 :                 break;
     134              :             }
     135              :     }
     136        37262 : }
     137              : 
     138              : const char *
     139        37267 : btree_identify(uint8 info)
     140              : {
     141        37267 :     const char *id = NULL;
     142              : 
     143        37267 :     switch (info & ~XLR_INFO_MASK)
     144              :     {
     145        36699 :         case XLOG_BTREE_INSERT_LEAF:
     146        36699 :             id = "INSERT_LEAF";
     147        36699 :             break;
     148           93 :         case XLOG_BTREE_INSERT_UPPER:
     149           93 :             id = "INSERT_UPPER";
     150           93 :             break;
     151            0 :         case XLOG_BTREE_INSERT_META:
     152            0 :             id = "INSERT_META";
     153            0 :             break;
     154           28 :         case XLOG_BTREE_SPLIT_L:
     155           28 :             id = "SPLIT_L";
     156           28 :             break;
     157           91 :         case XLOG_BTREE_SPLIT_R:
     158           91 :             id = "SPLIT_R";
     159           91 :             break;
     160            0 :         case XLOG_BTREE_INSERT_POST:
     161            0 :             id = "INSERT_POST";
     162            0 :             break;
     163           98 :         case XLOG_BTREE_DEDUP:
     164           98 :             id = "DEDUP";
     165           98 :             break;
     166          133 :         case XLOG_BTREE_VACUUM:
     167          133 :             id = "VACUUM";
     168          133 :             break;
     169           14 :         case XLOG_BTREE_DELETE:
     170           14 :             id = "DELETE";
     171           14 :             break;
     172            0 :         case XLOG_BTREE_MARK_PAGE_HALFDEAD:
     173            0 :             id = "MARK_PAGE_HALFDEAD";
     174            0 :             break;
     175            0 :         case XLOG_BTREE_UNLINK_PAGE:
     176            0 :             id = "UNLINK_PAGE";
     177            0 :             break;
     178            0 :         case XLOG_BTREE_UNLINK_PAGE_META:
     179            0 :             id = "UNLINK_PAGE_META";
     180            0 :             break;
     181          111 :         case XLOG_BTREE_NEWROOT:
     182          111 :             id = "NEWROOT";
     183          111 :             break;
     184            0 :         case XLOG_BTREE_REUSE_PAGE:
     185            0 :             id = "REUSE_PAGE";
     186            0 :             break;
     187            0 :         case XLOG_BTREE_META_CLEANUP:
     188            0 :             id = "META_CLEANUP";
     189            0 :             break;
     190              :     }
     191              : 
     192        37267 :     return id;
     193              : }
     194              : 
     195              : static void
     196          146 : delvacuum_desc(StringInfo buf, char *block_data,
     197              :                uint16 ndeleted, uint16 nupdated)
     198              : {
     199              :     OffsetNumber *deletedoffsets;
     200              :     OffsetNumber *updatedoffsets;
     201              :     xl_btree_update *updates;
     202              : 
     203              :     /* Output deleted page offset number array */
     204          146 :     appendStringInfoString(buf, ", deleted:");
     205          146 :     deletedoffsets = (OffsetNumber *) block_data;
     206          146 :     array_desc(buf, deletedoffsets, sizeof(OffsetNumber), ndeleted,
     207              :                &offset_elem_desc, NULL);
     208              : 
     209              :     /*
     210              :      * Output updates as an array of "update objects", where each element
     211              :      * contains a page offset number from updated array.  (This is not the
     212              :      * most literal representation of the underlying physical data structure
     213              :      * that we could use.  Readability seems more important here.)
     214              :      */
     215          146 :     appendStringInfoString(buf, ", updated: [");
     216          146 :     updatedoffsets = (OffsetNumber *) (block_data + ndeleted *
     217              :                                        sizeof(OffsetNumber));
     218          146 :     updates = (xl_btree_update *) ((char *) updatedoffsets +
     219          146 :                                    nupdated *
     220              :                                    sizeof(OffsetNumber));
     221          648 :     for (int i = 0; i < nupdated; i++)
     222              :     {
     223          502 :         OffsetNumber off = updatedoffsets[i];
     224              : 
     225              :         Assert(OffsetNumberIsValid(off));
     226              :         Assert(updates->ndeletedtids > 0);
     227              : 
     228              :         /*
     229              :          * "ptid" is the symbol name used when building each xl_btree_update's
     230              :          * array of offsets into a posting list tuple's ItemPointerData array.
     231              :          * xl_btree_update describes a subset of the existing TIDs to delete.
     232              :          */
     233          502 :         appendStringInfo(buf, "{ off: %u, nptids: %u, ptids: [",
     234          502 :                          off, updates->ndeletedtids);
     235         1160 :         for (int p = 0; p < updates->ndeletedtids; p++)
     236              :         {
     237              :             uint16     *ptid;
     238              : 
     239          658 :             ptid = (uint16 *) ((char *) updates + SizeOfBtreeUpdate) + p;
     240          658 :             appendStringInfo(buf, "%u", *ptid);
     241              : 
     242          658 :             if (p < updates->ndeletedtids - 1)
     243          156 :                 appendStringInfoString(buf, ", ");
     244              :         }
     245          502 :         appendStringInfoString(buf, "] }");
     246          502 :         if (i < nupdated - 1)
     247          480 :             appendStringInfoString(buf, ", ");
     248              : 
     249          502 :         updates = (xl_btree_update *)
     250          502 :             ((char *) updates + SizeOfBtreeUpdate +
     251          502 :              updates->ndeletedtids * sizeof(uint16));
     252              :     }
     253          146 :     appendStringInfoChar(buf, ']');
     254          146 : }
        

Generated by: LCOV version 2.0-1