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

Generated by: LCOV version 2.0-1