Coverage Report

Created: 2025-09-27 06:52

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