LCOV - code coverage report
Current view: top level - src/backend/backup - walsummaryfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 14 64 21.9 %
Date: 2025-10-10 18:17:38 Functions: 1 3 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * walsummaryfuncs.c
       4             :  *    SQL-callable functions for accessing WAL summary data.
       5             :  *
       6             :  * Portions Copyright (c) 2010-2025, PostgreSQL Global Development Group
       7             :  *
       8             :  * src/backend/backup/walsummaryfuncs.c
       9             :  *
      10             :  *-------------------------------------------------------------------------
      11             :  */
      12             : 
      13             : #include "postgres.h"
      14             : 
      15             : #include "access/htup_details.h"
      16             : #include "backup/walsummary.h"
      17             : #include "common/blkreftable.h"
      18             : #include "funcapi.h"
      19             : #include "miscadmin.h"
      20             : #include "postmaster/walsummarizer.h"
      21             : #include "utils/fmgrprotos.h"
      22             : #include "utils/pg_lsn.h"
      23             : 
      24             : #define NUM_WS_ATTS         3
      25             : #define NUM_SUMMARY_ATTS    6
      26             : #define NUM_STATE_ATTS      4
      27             : #define MAX_BLOCKS_PER_CALL 256
      28             : 
      29             : /*
      30             :  * List the WAL summary files available in pg_wal/summaries.
      31             :  */
      32             : Datum
      33           4 : pg_available_wal_summaries(PG_FUNCTION_ARGS)
      34             : {
      35             :     ReturnSetInfo *rsi;
      36             :     List       *wslist;
      37             :     ListCell   *lc;
      38             :     Datum       values[NUM_WS_ATTS];
      39             :     bool        nulls[NUM_WS_ATTS];
      40             : 
      41           4 :     InitMaterializedSRF(fcinfo, 0);
      42           4 :     rsi = (ReturnSetInfo *) fcinfo->resultinfo;
      43             : 
      44           4 :     memset(nulls, 0, sizeof(nulls));
      45             : 
      46           4 :     wslist = GetWalSummaries(0, InvalidXLogRecPtr, InvalidXLogRecPtr);
      47          36 :     foreach(lc, wslist)
      48             :     {
      49          32 :         WalSummaryFile *ws = (WalSummaryFile *) lfirst(lc);
      50             :         HeapTuple   tuple;
      51             : 
      52          32 :         CHECK_FOR_INTERRUPTS();
      53             : 
      54          32 :         values[0] = Int64GetDatum((int64) ws->tli);
      55          32 :         values[1] = LSNGetDatum(ws->start_lsn);
      56          32 :         values[2] = LSNGetDatum(ws->end_lsn);
      57             : 
      58          32 :         tuple = heap_form_tuple(rsi->setDesc, values, nulls);
      59          32 :         tuplestore_puttuple(rsi->setResult, tuple);
      60             :     }
      61             : 
      62           4 :     return (Datum) 0;
      63             : }
      64             : 
      65             : /*
      66             :  * List the contents of a WAL summary file identified by TLI, start LSN,
      67             :  * and end LSN.
      68             :  */
      69             : Datum
      70           0 : pg_wal_summary_contents(PG_FUNCTION_ARGS)
      71             : {
      72             :     ReturnSetInfo *rsi;
      73             :     Datum       values[NUM_SUMMARY_ATTS];
      74             :     bool        nulls[NUM_SUMMARY_ATTS];
      75             :     WalSummaryFile ws;
      76             :     WalSummaryIO io;
      77             :     BlockRefTableReader *reader;
      78             :     int64       raw_tli;
      79             :     RelFileLocator rlocator;
      80             :     ForkNumber  forknum;
      81             :     BlockNumber limit_block;
      82             : 
      83           0 :     InitMaterializedSRF(fcinfo, 0);
      84           0 :     rsi = (ReturnSetInfo *) fcinfo->resultinfo;
      85           0 :     memset(nulls, 0, sizeof(nulls));
      86             : 
      87             :     /*
      88             :      * Since the timeline could at least in theory be more than 2^31, and
      89             :      * since we don't have unsigned types at the SQL level, it is passed as a
      90             :      * 64-bit integer. Test whether it's out of range.
      91             :      */
      92           0 :     raw_tli = PG_GETARG_INT64(0);
      93           0 :     if (raw_tli < 1 || raw_tli > PG_INT32_MAX)
      94           0 :         ereport(ERROR,
      95             :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      96             :                 errmsg("invalid timeline %" PRId64, raw_tli));
      97             : 
      98             :     /* Prepare to read the specified WAL summary file. */
      99           0 :     ws.tli = (TimeLineID) raw_tli;
     100           0 :     ws.start_lsn = PG_GETARG_LSN(1);
     101           0 :     ws.end_lsn = PG_GETARG_LSN(2);
     102           0 :     io.filepos = 0;
     103           0 :     io.file = OpenWalSummaryFile(&ws, false);
     104           0 :     reader = CreateBlockRefTableReader(ReadWalSummary, &io,
     105             :                                        FilePathName(io.file),
     106             :                                        ReportWalSummaryError, NULL);
     107             : 
     108             :     /* Loop over relation forks. */
     109           0 :     while (BlockRefTableReaderNextRelation(reader, &rlocator, &forknum,
     110             :                                            &limit_block))
     111             :     {
     112             :         BlockNumber blocks[MAX_BLOCKS_PER_CALL];
     113             :         HeapTuple   tuple;
     114             : 
     115           0 :         CHECK_FOR_INTERRUPTS();
     116             : 
     117           0 :         values[0] = ObjectIdGetDatum(rlocator.relNumber);
     118           0 :         values[1] = ObjectIdGetDatum(rlocator.spcOid);
     119           0 :         values[2] = ObjectIdGetDatum(rlocator.dbOid);
     120           0 :         values[3] = Int16GetDatum((int16) forknum);
     121             : 
     122             :         /*
     123             :          * If the limit block is not InvalidBlockNumber, emit an extra row
     124             :          * with that block number and limit_block = true.
     125             :          *
     126             :          * There is no point in doing this when the limit_block is
     127             :          * InvalidBlockNumber, because no block with that number or any higher
     128             :          * number can ever exist.
     129             :          */
     130           0 :         if (BlockNumberIsValid(limit_block))
     131             :         {
     132           0 :             values[4] = Int64GetDatum((int64) limit_block);
     133           0 :             values[5] = BoolGetDatum(true);
     134             : 
     135           0 :             tuple = heap_form_tuple(rsi->setDesc, values, nulls);
     136           0 :             tuplestore_puttuple(rsi->setResult, tuple);
     137             :         }
     138             : 
     139             :         /* Loop over blocks within the current relation fork. */
     140             :         while (1)
     141           0 :         {
     142             :             unsigned    nblocks;
     143             :             unsigned    i;
     144             : 
     145           0 :             CHECK_FOR_INTERRUPTS();
     146             : 
     147           0 :             nblocks = BlockRefTableReaderGetBlocks(reader, blocks,
     148             :                                                    MAX_BLOCKS_PER_CALL);
     149           0 :             if (nblocks == 0)
     150           0 :                 break;
     151             : 
     152             :             /*
     153             :              * For each block that we specifically know to have been modified,
     154             :              * emit a row with that block number and limit_block = false.
     155             :              */
     156           0 :             values[5] = BoolGetDatum(false);
     157           0 :             for (i = 0; i < nblocks; ++i)
     158             :             {
     159           0 :                 values[4] = Int64GetDatum((int64) blocks[i]);
     160             : 
     161           0 :                 tuple = heap_form_tuple(rsi->setDesc, values, nulls);
     162           0 :                 tuplestore_puttuple(rsi->setResult, tuple);
     163             :             }
     164             :         }
     165             :     }
     166             : 
     167             :     /* Cleanup */
     168           0 :     DestroyBlockRefTableReader(reader);
     169           0 :     FileClose(io.file);
     170             : 
     171           0 :     return (Datum) 0;
     172             : }
     173             : 
     174             : /*
     175             :  * Returns information about the state of the WAL summarizer process.
     176             :  */
     177             : Datum
     178           0 : pg_get_wal_summarizer_state(PG_FUNCTION_ARGS)
     179             : {
     180             :     Datum       values[NUM_STATE_ATTS];
     181             :     bool        nulls[NUM_STATE_ATTS];
     182             :     TimeLineID  summarized_tli;
     183             :     XLogRecPtr  summarized_lsn;
     184             :     XLogRecPtr  pending_lsn;
     185             :     int         summarizer_pid;
     186             :     TupleDesc   tupdesc;
     187             :     HeapTuple   htup;
     188             : 
     189           0 :     GetWalSummarizerState(&summarized_tli, &summarized_lsn, &pending_lsn,
     190             :                           &summarizer_pid);
     191             : 
     192           0 :     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
     193           0 :         elog(ERROR, "return type must be a row type");
     194             : 
     195           0 :     memset(nulls, 0, sizeof(nulls));
     196             : 
     197           0 :     values[0] = Int64GetDatum((int64) summarized_tli);
     198           0 :     values[1] = LSNGetDatum(summarized_lsn);
     199           0 :     values[2] = LSNGetDatum(pending_lsn);
     200             : 
     201           0 :     if (summarizer_pid < 0)
     202           0 :         nulls[3] = true;
     203             :     else
     204           0 :         values[3] = Int32GetDatum(summarizer_pid);
     205             : 
     206           0 :     htup = heap_form_tuple(tupdesc, values, nulls);
     207             : 
     208           0 :     PG_RETURN_DATUM(HeapTupleGetDatum(htup));
     209             : }

Generated by: LCOV version 1.16