LCOV - code coverage report
Current view: top level - src/bin/pg_waldump - heapdesc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 220 245 89.8 %
Date: 2024-03-29 02:11:11 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * heapdesc.c
       4             :  *    rmgr descriptor routines for access/heap/heapam.c
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/access/rmgrdesc/heapdesc.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "access/heapam_xlog.h"
      18             : #include "access/rmgrdesc_utils.h"
      19             : 
      20             : /*
      21             :  * NOTE: "keyname" argument cannot have trailing spaces or punctuation
      22             :  * characters
      23             :  */
      24             : static void
      25      124250 : infobits_desc(StringInfo buf, uint8 infobits, const char *keyname)
      26             : {
      27      124250 :     appendStringInfo(buf, "%s: [", keyname);
      28             : 
      29             :     Assert(buf->data[buf->len - 1] != ' ');
      30             : 
      31      124250 :     if (infobits & XLHL_XMAX_IS_MULTI)
      32           0 :         appendStringInfoString(buf, "IS_MULTI, ");
      33      124250 :     if (infobits & XLHL_XMAX_LOCK_ONLY)
      34       60972 :         appendStringInfoString(buf, "LOCK_ONLY, ");
      35      124250 :     if (infobits & XLHL_XMAX_EXCL_LOCK)
      36       60972 :         appendStringInfoString(buf, "EXCL_LOCK, ");
      37      124250 :     if (infobits & XLHL_XMAX_KEYSHR_LOCK)
      38           0 :         appendStringInfoString(buf, "KEYSHR_LOCK, ");
      39      124250 :     if (infobits & XLHL_KEYS_UPDATED)
      40         630 :         appendStringInfoString(buf, "KEYS_UPDATED, ");
      41             : 
      42      124250 :     if (buf->data[buf->len - 1] == ' ')
      43             :     {
      44             :         /* Truncate-away final unneeded ", "  */
      45             :         Assert(buf->data[buf->len - 2] == ',');
      46       61602 :         buf->len -= 2;
      47       61602 :         buf->data[buf->len] = '\0';
      48             :     }
      49             : 
      50      124250 :     appendStringInfoChar(buf, ']');
      51      124250 : }
      52             : 
      53             : static void
      54          12 : truncate_flags_desc(StringInfo buf, uint8 flags)
      55             : {
      56          12 :     appendStringInfoString(buf, "flags: [");
      57             : 
      58          12 :     if (flags & XLH_TRUNCATE_CASCADE)
      59           0 :         appendStringInfoString(buf, "CASCADE, ");
      60          12 :     if (flags & XLH_TRUNCATE_RESTART_SEQS)
      61           0 :         appendStringInfoString(buf, "RESTART_SEQS, ");
      62             : 
      63          12 :     if (buf->data[buf->len - 1] == ' ')
      64             :     {
      65             :         /* Truncate-away final unneeded ", "  */
      66             :         Assert(buf->data[buf->len - 2] == ',');
      67           0 :         buf->len -= 2;
      68           0 :         buf->data[buf->len] = '\0';
      69             :     }
      70             : 
      71          12 :     appendStringInfoChar(buf, ']');
      72          12 : }
      73             : 
      74             : static void
      75        1176 : plan_elem_desc(StringInfo buf, void *plan, void *data)
      76             : {
      77        1176 :     xlhp_freeze_plan *new_plan = (xlhp_freeze_plan *) plan;
      78        1176 :     OffsetNumber **offsets = data;
      79             : 
      80        1176 :     appendStringInfo(buf, "{ xmax: %u, infomask: %u, infomask2: %u, ntuples: %u",
      81             :                      new_plan->xmax,
      82        1176 :                      new_plan->t_infomask, new_plan->t_infomask2,
      83        1176 :                      new_plan->ntuples);
      84             : 
      85        1176 :     appendStringInfoString(buf, ", offsets:");
      86        1176 :     array_desc(buf, *offsets, sizeof(OffsetNumber), new_plan->ntuples,
      87             :                &offset_elem_desc, NULL);
      88             : 
      89        1176 :     *offsets += new_plan->ntuples;
      90             : 
      91        1176 :     appendStringInfoString(buf, " }");
      92        1176 : }
      93             : 
      94             : 
      95             : /*
      96             :  * Given a MAXALIGNed buffer returned by XLogRecGetBlockData() and pointed to
      97             :  * by cursor and any xl_heap_prune flags, deserialize the arrays of
      98             :  * OffsetNumbers contained in an XLOG_HEAP2_PRUNE_* record.
      99             :  *
     100             :  * This is in heapdesc.c so it can be shared between heap2_redo and heap2_desc
     101             :  * code, the latter of which is used in frontend (pg_waldump) code.
     102             :  */
     103             : void
     104        3020 : heap_xlog_deserialize_prune_and_freeze(char *cursor, uint8 flags,
     105             :                                        int *nplans, xlhp_freeze_plan **plans,
     106             :                                        OffsetNumber **frz_offsets,
     107             :                                        int *nredirected, OffsetNumber **redirected,
     108             :                                        int *ndead, OffsetNumber **nowdead,
     109             :                                        int *nunused, OffsetNumber **nowunused)
     110             : {
     111        3020 :     if (flags & XLHP_HAS_FREEZE_PLANS)
     112             :     {
     113         968 :         xlhp_freeze_plans *freeze_plans = (xlhp_freeze_plans *) cursor;
     114             : 
     115         968 :         *nplans = freeze_plans->nplans;
     116             :         Assert(*nplans > 0);
     117         968 :         *plans = freeze_plans->plans;
     118             : 
     119         968 :         cursor += offsetof(xlhp_freeze_plans, plans);
     120         968 :         cursor += sizeof(xlhp_freeze_plan) * *nplans;
     121             :     }
     122             :     else
     123             :     {
     124        2052 :         *nplans = 0;
     125        2052 :         *plans = NULL;
     126             :     }
     127             : 
     128        3020 :     if (flags & XLHP_HAS_REDIRECTIONS)
     129             :     {
     130         700 :         xlhp_prune_items *subrecord = (xlhp_prune_items *) cursor;
     131             : 
     132         700 :         *nredirected = subrecord->ntargets;
     133             :         Assert(*nredirected > 0);
     134         700 :         *redirected = &subrecord->data[0];
     135             : 
     136         700 :         cursor += offsetof(xlhp_prune_items, data);
     137         700 :         cursor += sizeof(OffsetNumber[2]) * *nredirected;
     138             :     }
     139             :     else
     140             :     {
     141        2320 :         *nredirected = 0;
     142        2320 :         *redirected = NULL;
     143             :     }
     144             : 
     145        3020 :     if (flags & XLHP_HAS_DEAD_ITEMS)
     146             :     {
     147         828 :         xlhp_prune_items *subrecord = (xlhp_prune_items *) cursor;
     148             : 
     149         828 :         *ndead = subrecord->ntargets;
     150             :         Assert(*ndead > 0);
     151         828 :         *nowdead = subrecord->data;
     152             : 
     153         828 :         cursor += offsetof(xlhp_prune_items, data);
     154         828 :         cursor += sizeof(OffsetNumber) * *ndead;
     155             :     }
     156             :     else
     157             :     {
     158        2192 :         *ndead = 0;
     159        2192 :         *nowdead = NULL;
     160             :     }
     161             : 
     162        3020 :     if (flags & XLHP_HAS_NOW_UNUSED_ITEMS)
     163             :     {
     164         732 :         xlhp_prune_items *subrecord = (xlhp_prune_items *) cursor;
     165             : 
     166         732 :         *nunused = subrecord->ntargets;
     167             :         Assert(*nunused > 0);
     168         732 :         *nowunused = subrecord->data;
     169             : 
     170         732 :         cursor += offsetof(xlhp_prune_items, data);
     171         732 :         cursor += sizeof(OffsetNumber) * *nunused;
     172             :     }
     173             :     else
     174             :     {
     175        2288 :         *nunused = 0;
     176        2288 :         *nowunused = NULL;
     177             :     }
     178             : 
     179        3020 :     *frz_offsets = (OffsetNumber *) cursor;
     180        3020 : }
     181             : 
     182             : void
     183      270370 : heap_desc(StringInfo buf, XLogReaderState *record)
     184             : {
     185      270370 :     char       *rec = XLogRecGetData(record);
     186      270370 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
     187             : 
     188      270370 :     info &= XLOG_HEAP_OPMASK;
     189      270370 :     if (info == XLOG_HEAP_INSERT)
     190             :     {
     191      143462 :         xl_heap_insert *xlrec = (xl_heap_insert *) rec;
     192             : 
     193      143462 :         appendStringInfo(buf, "off: %u, flags: 0x%02X",
     194      143462 :                          xlrec->offnum,
     195      143462 :                          xlrec->flags);
     196             :     }
     197      126908 :     else if (info == XLOG_HEAP_DELETE)
     198             :     {
     199         630 :         xl_heap_delete *xlrec = (xl_heap_delete *) rec;
     200             : 
     201         630 :         appendStringInfo(buf, "xmax: %u, off: %u, ",
     202         630 :                          xlrec->xmax, xlrec->offnum);
     203         630 :         infobits_desc(buf, xlrec->infobits_set, "infobits");
     204         630 :         appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
     205             :     }
     206      126278 :     else if (info == XLOG_HEAP_UPDATE)
     207             :     {
     208       61032 :         xl_heap_update *xlrec = (xl_heap_update *) rec;
     209             : 
     210       61032 :         appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
     211       61032 :                          xlrec->old_xmax, xlrec->old_offnum);
     212       61032 :         infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
     213       61032 :         appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
     214       61032 :                          xlrec->flags, xlrec->new_xmax, xlrec->new_offnum);
     215             :     }
     216       65246 :     else if (info == XLOG_HEAP_HOT_UPDATE)
     217             :     {
     218        1616 :         xl_heap_update *xlrec = (xl_heap_update *) rec;
     219             : 
     220        1616 :         appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
     221        1616 :                          xlrec->old_xmax, xlrec->old_offnum);
     222        1616 :         infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
     223        1616 :         appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
     224        1616 :                          xlrec->flags, xlrec->new_xmax, xlrec->new_offnum);
     225             :     }
     226       63630 :     else if (info == XLOG_HEAP_TRUNCATE)
     227             :     {
     228          12 :         xl_heap_truncate *xlrec = (xl_heap_truncate *) rec;
     229             : 
     230          12 :         truncate_flags_desc(buf, xlrec->flags);
     231          12 :         appendStringInfo(buf, ", nrelids: %u", xlrec->nrelids);
     232          12 :         appendStringInfoString(buf, ", relids:");
     233          12 :         array_desc(buf, xlrec->relids, sizeof(Oid), xlrec->nrelids,
     234             :                    &oid_elem_desc, NULL);
     235             :     }
     236       63618 :     else if (info == XLOG_HEAP_CONFIRM)
     237             :     {
     238           0 :         xl_heap_confirm *xlrec = (xl_heap_confirm *) rec;
     239             : 
     240           0 :         appendStringInfo(buf, "off: %u", xlrec->offnum);
     241             :     }
     242       63618 :     else if (info == XLOG_HEAP_LOCK)
     243             :     {
     244       60972 :         xl_heap_lock *xlrec = (xl_heap_lock *) rec;
     245             : 
     246       60972 :         appendStringInfo(buf, "xmax: %u, off: %u, ",
     247       60972 :                          xlrec->xmax, xlrec->offnum);
     248       60972 :         infobits_desc(buf, xlrec->infobits_set, "infobits");
     249       60972 :         appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
     250             :     }
     251        2646 :     else if (info == XLOG_HEAP_INPLACE)
     252             :     {
     253        2646 :         xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
     254             : 
     255        2646 :         appendStringInfo(buf, "off: %u", xlrec->offnum);
     256             :     }
     257      270370 : }
     258             : 
     259             : void
     260       17574 : heap2_desc(StringInfo buf, XLogReaderState *record)
     261             : {
     262       17574 :     char       *rec = XLogRecGetData(record);
     263       17574 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
     264             : 
     265       17574 :     info &= XLOG_HEAP_OPMASK;
     266       17574 :     if (info == XLOG_HEAP2_PRUNE_ON_ACCESS ||
     267       15096 :         info == XLOG_HEAP2_PRUNE_VACUUM_SCAN ||
     268             :         info == XLOG_HEAP2_PRUNE_VACUUM_CLEANUP)
     269        3034 :     {
     270        3034 :         xl_heap_prune *xlrec = (xl_heap_prune *) rec;
     271             : 
     272        3034 :         if (xlrec->flags & XLHP_HAS_CONFLICT_HORIZON)
     273             :         {
     274             :             TransactionId conflict_xid;
     275             : 
     276        2336 :             memcpy(&conflict_xid, rec + SizeOfHeapPrune, sizeof(TransactionId));
     277             : 
     278        2336 :             appendStringInfo(buf, "snapshotConflictHorizon: %u",
     279             :                              conflict_xid);
     280             :         }
     281             : 
     282        3034 :         appendStringInfo(buf, ", isCatalogRel: %c",
     283        3034 :                          xlrec->flags & XLHP_IS_CATALOG_REL ? 'T' : 'F');
     284             : 
     285        3034 :         if (XLogRecHasBlockData(record, 0))
     286             :         {
     287             :             Size        datalen;
     288             :             OffsetNumber *redirected;
     289             :             OffsetNumber *nowdead;
     290             :             OffsetNumber *nowunused;
     291             :             int         nredirected;
     292             :             int         nunused;
     293             :             int         ndead;
     294             :             int         nplans;
     295             :             xlhp_freeze_plan *plans;
     296             :             OffsetNumber *frz_offsets;
     297             : 
     298        3020 :             char       *cursor = XLogRecGetBlockData(record, 0, &datalen);
     299             : 
     300        3020 :             heap_xlog_deserialize_prune_and_freeze(cursor, xlrec->flags,
     301             :                                                    &nplans, &plans, &frz_offsets,
     302             :                                                    &nredirected, &redirected,
     303             :                                                    &ndead, &nowdead,
     304             :                                                    &nunused, &nowunused);
     305             : 
     306        3020 :             appendStringInfo(buf, ", nplans: %u, nredirected: %u, ndead: %u, nunused: %u",
     307             :                              nplans, nredirected, ndead, nunused);
     308             : 
     309        3020 :             if (nplans > 0)
     310             :             {
     311         968 :                 appendStringInfoString(buf, ", plans:");
     312         968 :                 array_desc(buf, plans, sizeof(xlhp_freeze_plan), nplans,
     313             :                            &plan_elem_desc, &frz_offsets);
     314             :             }
     315             : 
     316        3020 :             if (nredirected > 0)
     317             :             {
     318         700 :                 appendStringInfoString(buf, ", redirected:");
     319         700 :                 array_desc(buf, redirected, sizeof(OffsetNumber) * 2,
     320             :                            nredirected, &redirect_elem_desc, NULL);
     321             :             }
     322             : 
     323        3020 :             if (ndead > 0)
     324             :             {
     325         828 :                 appendStringInfoString(buf, ", dead:");
     326         828 :                 array_desc(buf, nowdead, sizeof(OffsetNumber), ndead,
     327             :                            &offset_elem_desc, NULL);
     328             :             }
     329             : 
     330        3020 :             if (nunused > 0)
     331             :             {
     332         732 :                 appendStringInfoString(buf, ", unused:");
     333         732 :                 array_desc(buf, nowunused, sizeof(OffsetNumber), nunused,
     334             :                            &offset_elem_desc, NULL);
     335             :             }
     336             :         }
     337             :     }
     338       14540 :     else if (info == XLOG_HEAP2_VISIBLE)
     339             :     {
     340        3092 :         xl_heap_visible *xlrec = (xl_heap_visible *) rec;
     341             : 
     342        3092 :         appendStringInfo(buf, "snapshotConflictHorizon: %u, flags: 0x%02X",
     343        3092 :                          xlrec->snapshotConflictHorizon, xlrec->flags);
     344             :     }
     345       11448 :     else if (info == XLOG_HEAP2_MULTI_INSERT)
     346             :     {
     347        7690 :         xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
     348        7690 :         bool        isinit = (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE) != 0;
     349             : 
     350        7690 :         appendStringInfo(buf, "ntuples: %d, flags: 0x%02X", xlrec->ntuples,
     351        7690 :                          xlrec->flags);
     352             : 
     353        7690 :         if (XLogRecHasBlockData(record, 0) && !isinit)
     354             :         {
     355        7388 :             appendStringInfoString(buf, ", offsets:");
     356        7388 :             array_desc(buf, xlrec->offsets, sizeof(OffsetNumber),
     357        7388 :                        xlrec->ntuples, &offset_elem_desc, NULL);
     358             :         }
     359             :     }
     360        3758 :     else if (info == XLOG_HEAP2_LOCK_UPDATED)
     361             :     {
     362           0 :         xl_heap_lock_updated *xlrec = (xl_heap_lock_updated *) rec;
     363             : 
     364           0 :         appendStringInfo(buf, "xmax: %u, off: %u, ",
     365           0 :                          xlrec->xmax, xlrec->offnum);
     366           0 :         infobits_desc(buf, xlrec->infobits_set, "infobits");
     367           0 :         appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
     368             :     }
     369        3758 :     else if (info == XLOG_HEAP2_NEW_CID)
     370             :     {
     371        3758 :         xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec;
     372             : 
     373        3758 :         appendStringInfo(buf, "rel: %u/%u/%u, tid: %u/%u",
     374             :                          xlrec->target_locator.spcOid,
     375             :                          xlrec->target_locator.dbOid,
     376             :                          xlrec->target_locator.relNumber,
     377        3758 :                          ItemPointerGetBlockNumber(&(xlrec->target_tid)),
     378        3758 :                          ItemPointerGetOffsetNumber(&(xlrec->target_tid)));
     379        3758 :         appendStringInfo(buf, ", cmin: %u, cmax: %u, combo: %u",
     380             :                          xlrec->cmin, xlrec->cmax, xlrec->combocid);
     381             :     }
     382       17574 : }
     383             : 
     384             : const char *
     385      270388 : heap_identify(uint8 info)
     386             : {
     387      270388 :     const char *id = NULL;
     388             : 
     389      270388 :     switch (info & ~XLR_INFO_MASK)
     390             :     {
     391      142066 :         case XLOG_HEAP_INSERT:
     392      142066 :             id = "INSERT";
     393      142066 :             break;
     394        1400 :         case XLOG_HEAP_INSERT | XLOG_HEAP_INIT_PAGE:
     395        1400 :             id = "INSERT+INIT";
     396        1400 :             break;
     397         632 :         case XLOG_HEAP_DELETE:
     398         632 :             id = "DELETE";
     399         632 :             break;
     400       60590 :         case XLOG_HEAP_UPDATE:
     401       60590 :             id = "UPDATE";
     402       60590 :             break;
     403         446 :         case XLOG_HEAP_UPDATE | XLOG_HEAP_INIT_PAGE:
     404         446 :             id = "UPDATE+INIT";
     405         446 :             break;
     406        1618 :         case XLOG_HEAP_HOT_UPDATE:
     407        1618 :             id = "HOT_UPDATE";
     408        1618 :             break;
     409           0 :         case XLOG_HEAP_HOT_UPDATE | XLOG_HEAP_INIT_PAGE:
     410           0 :             id = "HOT_UPDATE+INIT";
     411           0 :             break;
     412          14 :         case XLOG_HEAP_TRUNCATE:
     413          14 :             id = "TRUNCATE";
     414          14 :             break;
     415           0 :         case XLOG_HEAP_CONFIRM:
     416           0 :             id = "HEAP_CONFIRM";
     417           0 :             break;
     418       60974 :         case XLOG_HEAP_LOCK:
     419       60974 :             id = "LOCK";
     420       60974 :             break;
     421        2648 :         case XLOG_HEAP_INPLACE:
     422        2648 :             id = "INPLACE";
     423        2648 :             break;
     424             :     }
     425             : 
     426      270388 :     return id;
     427             : }
     428             : 
     429             : const char *
     430       17588 : heap2_identify(uint8 info)
     431             : {
     432       17588 :     const char *id = NULL;
     433             : 
     434       17588 :     switch (info & ~XLR_INFO_MASK)
     435             :     {
     436        1104 :         case XLOG_HEAP2_PRUNE_ON_ACCESS:
     437        1104 :             id = "PRUNE_ON_ACCESS";
     438        1104 :             break;
     439        1378 :         case XLOG_HEAP2_PRUNE_VACUUM_SCAN:
     440        1378 :             id = "PRUNE_VACUUM_SCAN";
     441        1378 :             break;
     442         558 :         case XLOG_HEAP2_PRUNE_VACUUM_CLEANUP:
     443         558 :             id = "PRUNE_VACUUM_CLEANUP";
     444         558 :             break;
     445        3094 :         case XLOG_HEAP2_VISIBLE:
     446        3094 :             id = "VISIBLE";
     447        3094 :             break;
     448        7468 :         case XLOG_HEAP2_MULTI_INSERT:
     449        7468 :             id = "MULTI_INSERT";
     450        7468 :             break;
     451         226 :         case XLOG_HEAP2_MULTI_INSERT | XLOG_HEAP_INIT_PAGE:
     452         226 :             id = "MULTI_INSERT+INIT";
     453         226 :             break;
     454           0 :         case XLOG_HEAP2_LOCK_UPDATED:
     455           0 :             id = "LOCK_UPDATED";
     456           0 :             break;
     457        3760 :         case XLOG_HEAP2_NEW_CID:
     458        3760 :             id = "NEW_CID";
     459        3760 :             break;
     460           0 :         case XLOG_HEAP2_REWRITE:
     461           0 :             id = "REWRITE";
     462           0 :             break;
     463             :     }
     464             : 
     465       17588 :     return id;
     466             : }

Generated by: LCOV version 1.14