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 : }
|