Coverage Report

Created: 2025-10-09 06:07

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 "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
0
#define MAX_BLOCKS_PER_CALL 256
28
29
/*
30
 * List the WAL summary files available in pg_wal/summaries.
31
 */
32
Datum
33
pg_available_wal_summaries(PG_FUNCTION_ARGS)
34
0
{
35
0
  ReturnSetInfo *rsi;
36
0
  List     *wslist;
37
0
  ListCell   *lc;
38
0
  Datum   values[NUM_WS_ATTS];
39
0
  bool    nulls[NUM_WS_ATTS];
40
41
0
  InitMaterializedSRF(fcinfo, 0);
42
0
  rsi = (ReturnSetInfo *) fcinfo->resultinfo;
43
44
0
  memset(nulls, 0, sizeof(nulls));
45
46
0
  wslist = GetWalSummaries(0, InvalidXLogRecPtr, InvalidXLogRecPtr);
47
0
  foreach(lc, wslist)
48
0
  {
49
0
    WalSummaryFile *ws = (WalSummaryFile *) lfirst(lc);
50
0
    HeapTuple tuple;
51
52
0
    CHECK_FOR_INTERRUPTS();
53
54
0
    values[0] = Int64GetDatum((int64) ws->tli);
55
0
    values[1] = LSNGetDatum(ws->start_lsn);
56
0
    values[2] = LSNGetDatum(ws->end_lsn);
57
58
0
    tuple = heap_form_tuple(rsi->setDesc, values, nulls);
59
0
    tuplestore_puttuple(rsi->setResult, tuple);
60
0
  }
61
62
0
  return (Datum) 0;
63
0
}
64
65
/*
66
 * List the contents of a WAL summary file identified by TLI, start LSN,
67
 * and end LSN.
68
 */
69
Datum
70
pg_wal_summary_contents(PG_FUNCTION_ARGS)
71
0
{
72
0
  ReturnSetInfo *rsi;
73
0
  Datum   values[NUM_SUMMARY_ATTS];
74
0
  bool    nulls[NUM_SUMMARY_ATTS];
75
0
  WalSummaryFile ws;
76
0
  WalSummaryIO io;
77
0
  BlockRefTableReader *reader;
78
0
  int64   raw_tli;
79
0
  RelFileLocator rlocator;
80
0
  ForkNumber  forknum;
81
0
  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
0
        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
96
0
        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
0
                     FilePathName(io.file),
106
0
                     ReportWalSummaryError, NULL);
107
108
  /* Loop over relation forks. */
109
0
  while (BlockRefTableReaderNextRelation(reader, &rlocator, &forknum,
110
0
                       &limit_block))
111
0
  {
112
0
    BlockNumber blocks[MAX_BLOCKS_PER_CALL];
113
0
    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
0
    {
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
0
    }
138
139
    /* Loop over blocks within the current relation fork. */
140
0
    while (1)
141
0
    {
142
0
      unsigned  nblocks;
143
0
      unsigned  i;
144
145
0
      CHECK_FOR_INTERRUPTS();
146
147
0
      nblocks = BlockRefTableReaderGetBlocks(reader, blocks,
148
0
                           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
0
      {
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
0
      }
164
0
    }
165
0
  }
166
167
  /* Cleanup */
168
0
  DestroyBlockRefTableReader(reader);
169
0
  FileClose(io.file);
170
171
0
  return (Datum) 0;
172
0
}
173
174
/*
175
 * Returns information about the state of the WAL summarizer process.
176
 */
177
Datum
178
pg_get_wal_summarizer_state(PG_FUNCTION_ARGS)
179
0
{
180
0
  Datum   values[NUM_STATE_ATTS];
181
0
  bool    nulls[NUM_STATE_ATTS];
182
0
  TimeLineID  summarized_tli;
183
0
  XLogRecPtr  summarized_lsn;
184
0
  XLogRecPtr  pending_lsn;
185
0
  int     summarizer_pid;
186
0
  TupleDesc tupdesc;
187
0
  HeapTuple htup;
188
189
0
  GetWalSummarizerState(&summarized_tli, &summarized_lsn, &pending_lsn,
190
0
              &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
0
  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
0
}