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