Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * xlogdesc.c
4 : : * rmgr descriptor routines for access/transam/xlog.c
5 : : *
6 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/access/rmgrdesc/xlogdesc.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include "access/transam.h"
18 : : #include "access/xlog.h"
19 : : #include "access/xlog_internal.h"
20 : : #include "catalog/pg_control.h"
21 : : #include "utils/guc.h"
22 : : #include "utils/timestamp.h"
23 : :
24 : : /*
25 : : * GUC support
26 : : */
27 : : const struct config_enum_entry wal_level_options[] = {
28 : : {"minimal", WAL_LEVEL_MINIMAL, false},
29 : : {"replica", WAL_LEVEL_REPLICA, false},
30 : : {"archive", WAL_LEVEL_REPLICA, true}, /* deprecated */
31 : : {"hot_standby", WAL_LEVEL_REPLICA, true}, /* deprecated */
32 : : {"logical", WAL_LEVEL_LOGICAL, false},
33 : : {NULL, 0, false}
34 : : };
35 : :
36 : : /*
37 : : * Find a string representation for wal_level
38 : : */
39 : : static const char *
415 rhaas@postgresql.org 40 :CBC 43 : get_wal_level_string(int wal_level)
41 : : {
42 : : const struct config_enum_entry *entry;
43 : 43 : const char *wal_level_str = "?";
44 : :
45 [ + - ]: 129 : for (entry = wal_level_options; entry->name; entry++)
46 : : {
47 [ + + ]: 129 : if (entry->val == wal_level)
48 : : {
49 : 43 : wal_level_str = entry->name;
50 : 43 : break;
51 : : }
52 : : }
53 : :
54 : 43 : return wal_level_str;
55 : : }
56 : :
57 : : void
3943 heikki.linnakangas@i 58 : 7953 : xlog_desc(StringInfo buf, XLogReaderState *record)
59 : : {
4102 60 : 7953 : char *rec = XLogRecGetData(record);
3943 61 : 7953 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
62 : :
4665 alvherre@alvh.no-ip. 63 [ + + + + ]: 7953 : if (info == XLOG_CHECKPOINT_SHUTDOWN ||
64 : : info == XLOG_CHECKPOINT_ONLINE)
65 : 23 : {
66 : 23 : CheckPoint *checkpoint = (CheckPoint *) rec;
67 : :
61 alvherre@kurilemu.de 68 [ + + ]:GNC 46 : appendStringInfo(buf, "redo %X/%08X; "
69 : : "tli %u; prev tli %u; fpw %s; wal_level %s; xid %u:%u; oid %u; multi %u; offset %u; "
70 : : "oldest xid %u in DB %u; oldest multi %u in DB %u; "
71 : : "oldest/newest commit timestamp xid: %u/%u; "
72 : : "oldest running xid %u; %s",
1656 peter@eisentraut.org 73 :CBC 23 : LSN_FORMAT_ARGS(checkpoint->redo),
74 : : checkpoint->ThisTimeLineID,
75 : : checkpoint->PrevTimeLineID,
4665 alvherre@alvh.no-ip. 76 [ + + ]: 23 : checkpoint->fullPageWrites ? "true" : "false",
77 : : get_wal_level_string(checkpoint->wal_level),
1852 andres@anarazel.de 78 : 23 : EpochFromFullTransactionId(checkpoint->nextXid),
79 : 23 : XidFromFullTransactionId(checkpoint->nextXid),
80 : : checkpoint->nextOid,
81 : : checkpoint->nextMulti,
82 : : checkpoint->nextMultiOffset,
83 : : checkpoint->oldestXid,
84 : : checkpoint->oldestXidDB,
85 : : checkpoint->oldestMulti,
86 : : checkpoint->oldestMultiDB,
87 : : checkpoint->oldestCommitTsXid,
88 : : checkpoint->newestCommitTsXid,
89 : : checkpoint->oldestActiveXid,
90 : : (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
91 : : }
4665 alvherre@alvh.no-ip. 92 [ + + ]: 7930 : else if (info == XLOG_NEXTOID)
93 : : {
94 : : Oid nextOid;
95 : :
96 : 13 : memcpy(&nextOid, rec, sizeof(Oid));
4005 andres@anarazel.de 97 : 13 : appendStringInfo(buf, "%u", nextOid);
98 : : }
4665 alvherre@alvh.no-ip. 99 [ - + ]: 7917 : else if (info == XLOG_RESTORE_POINT)
100 : : {
4665 alvherre@alvh.no-ip. 101 :UBC 0 : xl_restore_point *xlrec = (xl_restore_point *) rec;
102 : :
3771 peter_e@gmx.net 103 : 0 : appendStringInfoString(buf, xlrec->rp_name);
104 : : }
3939 heikki.linnakangas@i 105 [ + + + + ]:CBC 7917 : else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
106 : : {
107 : : /* no further information to print */
108 : : }
4665 alvherre@alvh.no-ip. 109 [ + + ]: 30 : else if (info == XLOG_BACKUP_END)
110 : : {
111 : : XLogRecPtr startpoint;
112 : :
113 : 4 : memcpy(&startpoint, rec, sizeof(XLogRecPtr));
61 alvherre@kurilemu.de 114 :GNC 4 : appendStringInfo(buf, "%X/%08X", LSN_FORMAT_ARGS(startpoint));
115 : : }
4665 alvherre@alvh.no-ip. 116 [ + + ]:CBC 26 : else if (info == XLOG_PARAMETER_CHANGE)
117 : : {
118 : : xl_parameter_change xlrec;
119 : : const char *wal_level_str;
120 : :
121 : 5 : memcpy(&xlrec, rec, sizeof(xl_parameter_change));
415 rhaas@postgresql.org 122 : 5 : wal_level_str = get_wal_level_string(xlrec.wal_level);
123 : :
3928 heikki.linnakangas@i 124 : 10 : appendStringInfo(buf, "max_connections=%d max_worker_processes=%d "
125 : : "max_wal_senders=%d max_prepared_xacts=%d "
126 : : "max_locks_per_xact=%d wal_level=%s "
127 : : "wal_log_hints=%s track_commit_timestamp=%s",
128 : : xlrec.MaxConnections,
129 : : xlrec.max_worker_processes,
130 : : xlrec.max_wal_senders,
131 : : xlrec.max_prepared_xacts,
132 : : xlrec.max_locks_per_xact,
133 : : wal_level_str,
134 [ + + ]: 5 : xlrec.wal_log_hints ? "on" : "off",
135 [ - + ]: 5 : xlrec.track_commit_timestamp ? "on" : "off");
136 : : }
4665 alvherre@alvh.no-ip. 137 [ - + ]: 21 : else if (info == XLOG_FPW_CHANGE)
138 : : {
139 : : bool fpw;
140 : :
4665 alvherre@alvh.no-ip. 141 :UBC 0 : memcpy(&fpw, rec, sizeof(bool));
3771 peter_e@gmx.net 142 [ # # ]: 0 : appendStringInfoString(buf, fpw ? "true" : "false");
143 : : }
4603 simon@2ndQuadrant.co 144 [ - + ]:CBC 21 : else if (info == XLOG_END_OF_RECOVERY)
145 : : {
146 : : xl_end_of_recovery xlrec;
147 : :
4603 simon@2ndQuadrant.co 148 :UBC 0 : memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
415 rhaas@postgresql.org 149 : 0 : appendStringInfo(buf, "tli %u; prev tli %u; time %s; wal_level %s",
150 : : xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
151 : : timestamptz_to_str(xlrec.end_time),
152 : : get_wal_level_string(xlrec.wal_level));
153 : : }
1438 alvherre@alvh.no-ip. 154 [ + + ]:CBC 21 : else if (info == XLOG_OVERWRITE_CONTRECORD)
155 : : {
156 : : xl_overwrite_contrecord xlrec;
157 : :
158 : 1 : memcpy(&xlrec, rec, sizeof(xl_overwrite_contrecord));
61 alvherre@kurilemu.de 159 :GNC 1 : appendStringInfo(buf, "lsn %X/%08X; time %s",
1438 alvherre@alvh.no-ip. 160 :CBC 1 : LSN_FORMAT_ARGS(xlrec.overwritten_lsn),
161 : : timestamptz_to_str(xlrec.overwrite_time));
162 : : }
688 rhaas@postgresql.org 163 [ + + ]: 20 : else if (info == XLOG_CHECKPOINT_REDO)
164 : : {
165 : : int wal_level;
166 : :
415 167 : 15 : memcpy(&wal_level, rec, sizeof(int));
168 : 15 : appendStringInfo(buf, "wal_level %s", get_wal_level_string(wal_level));
169 : : }
4005 andres@anarazel.de 170 : 7953 : }
171 : :
172 : : const char *
173 : 7958 : xlog_identify(uint8 info)
174 : : {
175 : 7958 : const char *id = NULL;
176 : :
4002 177 [ + + - + : 7958 : switch (info & ~XLR_INFO_MASK)
+ + + - -
- + + + +
- ]
178 : : {
4005 179 : 9 : case XLOG_CHECKPOINT_SHUTDOWN:
180 : 9 : id = "CHECKPOINT_SHUTDOWN";
181 : 9 : break;
182 : 15 : case XLOG_CHECKPOINT_ONLINE:
183 : 15 : id = "CHECKPOINT_ONLINE";
184 : 15 : break;
4005 andres@anarazel.de 185 :UBC 0 : case XLOG_NOOP:
186 : 0 : id = "NOOP";
187 : 0 : break;
4005 andres@anarazel.de 188 :CBC 14 : case XLOG_NEXTOID:
189 : 14 : id = "NEXTOID";
190 : 14 : break;
191 : 5 : case XLOG_SWITCH:
192 : 5 : id = "SWITCH";
193 : 5 : break;
194 : 4 : case XLOG_BACKUP_END:
195 : 4 : id = "BACKUP_END";
196 : 4 : break;
197 : 5 : case XLOG_PARAMETER_CHANGE:
198 : 5 : id = "PARAMETER_CHANGE";
199 : 5 : break;
4005 andres@anarazel.de 200 :UBC 0 : case XLOG_RESTORE_POINT:
201 : 0 : id = "RESTORE_POINT";
202 : 0 : break;
203 : 0 : case XLOG_FPW_CHANGE:
204 : 0 : id = "FPW_CHANGE";
205 : 0 : break;
206 : 0 : case XLOG_END_OF_RECOVERY:
207 : 0 : id = "END_OF_RECOVERY";
208 : 0 : break;
1438 alvherre@alvh.no-ip. 209 :CBC 1 : case XLOG_OVERWRITE_CONTRECORD:
210 : 1 : id = "OVERWRITE_CONTRECORD";
211 : 1 : break;
4005 andres@anarazel.de 212 : 7238 : case XLOG_FPI:
213 : 7238 : id = "FPI";
214 : 7238 : break;
3939 heikki.linnakangas@i 215 : 651 : case XLOG_FPI_FOR_HINT:
216 : 651 : id = "FPI_FOR_HINT";
217 : 651 : break;
688 rhaas@postgresql.org 218 : 16 : case XLOG_CHECKPOINT_REDO:
219 : 16 : id = "CHECKPOINT_REDO";
220 : 16 : break;
221 : : }
222 : :
4005 andres@anarazel.de 223 : 7958 : return id;
224 : : }
225 : :
226 : : /*
227 : : * Returns a string giving information about all the blocks in an
228 : : * XLogRecord.
229 : : */
230 : : void
1247 jdavis@postgresql.or 231 : 296867 : XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty,
232 : : bool detailed_format, StringInfo buf,
233 : : uint32 *fpi_len)
234 : : {
235 : : int block_id;
236 : :
237 [ - + ]: 296867 : Assert(record != NULL);
238 : :
239 [ + + - + ]: 296867 : if (detailed_format && pretty)
1247 jdavis@postgresql.or 240 :UBC 0 : appendStringInfoChar(buf, '\n');
241 : :
1247 jdavis@postgresql.or 242 [ + + ]:CBC 623594 : for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
243 : : {
244 : : RelFileLocator rlocator;
245 : : ForkNumber forknum;
246 : : BlockNumber blk;
247 : :
1244 tgl@sss.pgh.pa.us 248 [ + + ]: 326727 : if (!XLogRecGetBlockTagExtended(record, block_id,
249 : : &rlocator, &forknum, &blk, NULL))
1247 jdavis@postgresql.or 250 : 92 : continue;
251 : :
252 [ + + ]: 326635 : if (detailed_format)
253 : : {
254 : : /* Get block references in detailed format. */
255 : :
256 [ - + ]: 36340 : if (pretty)
1247 jdavis@postgresql.or 257 :UBC 0 : appendStringInfoChar(buf, '\t');
1247 jdavis@postgresql.or 258 [ + + ]:CBC 36340 : else if (block_id > 0)
259 : 2011 : appendStringInfoChar(buf, ' ');
260 : :
261 : 36340 : appendStringInfo(buf,
262 : : "blkref #%d: rel %u/%u/%u fork %s blk %u",
263 : : block_id,
264 : : rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
265 : 36340 : forkNames[forknum],
266 : : blk);
267 : :
268 [ + + ]: 36340 : if (XLogRecHasBlockImage(record, block_id))
269 : : {
270 : 5264 : uint8 bimg_info = XLogRecGetBlock(record, block_id)->bimg_info;
271 : :
272 : : /* Calculate the amount of FPI data in the record. */
273 [ + - ]: 5264 : if (fpi_len)
274 : 5264 : *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
275 : :
276 [ - + ]: 5264 : if (BKPIMAGE_COMPRESSED(bimg_info))
277 : : {
278 : : const char *method;
279 : :
1247 jdavis@postgresql.or 280 [ # # ]:UBC 0 : if ((bimg_info & BKPIMAGE_COMPRESS_PGLZ) != 0)
281 : 0 : method = "pglz";
282 [ # # ]: 0 : else if ((bimg_info & BKPIMAGE_COMPRESS_LZ4) != 0)
283 : 0 : method = "lz4";
284 [ # # ]: 0 : else if ((bimg_info & BKPIMAGE_COMPRESS_ZSTD) != 0)
285 : 0 : method = "zstd";
286 : : else
287 : 0 : method = "unknown";
288 : :
289 : 0 : appendStringInfo(buf,
290 : : " (FPW%s); hole: offset: %u, length: %u, "
291 : : "compression saved: %u, method: %s",
292 : 0 : XLogRecBlockImageApply(record, block_id) ?
293 : : "" : " for WAL verification",
294 : 0 : XLogRecGetBlock(record, block_id)->hole_offset,
295 : 0 : XLogRecGetBlock(record, block_id)->hole_length,
296 : : BLCKSZ -
297 : 0 : XLogRecGetBlock(record, block_id)->hole_length -
298 [ # # ]: 0 : XLogRecGetBlock(record, block_id)->bimg_len,
299 : : method);
300 : : }
301 : : else
302 : : {
1247 jdavis@postgresql.or 303 :CBC 5264 : appendStringInfo(buf,
304 : : " (FPW%s); hole: offset: %u, length: %u",
305 : 5264 : XLogRecBlockImageApply(record, block_id) ?
306 : : "" : " for WAL verification",
307 : 5264 : XLogRecGetBlock(record, block_id)->hole_offset,
308 [ + + ]: 5264 : XLogRecGetBlock(record, block_id)->hole_length);
309 : : }
310 : : }
311 : :
312 [ - + ]: 36340 : if (pretty)
1247 jdavis@postgresql.or 313 :UBC 0 : appendStringInfoChar(buf, '\n');
314 : : }
315 : : else
316 : : {
317 : : /* Get block references in short format. */
318 : :
1247 jdavis@postgresql.or 319 [ + + ]:CBC 290295 : if (forknum != MAIN_FORKNUM)
320 : : {
321 : 3256 : appendStringInfo(buf,
322 : : ", blkref #%d: rel %u/%u/%u fork %s blk %u",
323 : : block_id,
324 : : rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
325 : 3256 : forkNames[forknum],
326 : : blk);
327 : : }
328 : : else
329 : : {
330 : 287039 : appendStringInfo(buf,
331 : : ", blkref #%d: rel %u/%u/%u blk %u",
332 : : block_id,
333 : : rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
334 : : blk);
335 : : }
336 : :
337 [ + + ]: 290295 : if (XLogRecHasBlockImage(record, block_id))
338 : : {
339 : : /* Calculate the amount of FPI data in the record. */
340 [ - + ]: 9356 : if (fpi_len)
1247 jdavis@postgresql.or 341 :UBC 0 : *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
342 : :
1247 jdavis@postgresql.or 343 [ + - ]:CBC 9356 : if (XLogRecBlockImageApply(record, block_id))
1096 drowley@postgresql.o 344 : 9356 : appendStringInfoString(buf, " FPW");
345 : : else
1096 drowley@postgresql.o 346 :UBC 0 : appendStringInfoString(buf, " FPW for WAL verification");
347 : : }
348 : : }
349 : : }
350 : :
1247 jdavis@postgresql.or 351 [ + + + - ]:CBC 296867 : if (!detailed_format && pretty)
352 : 262538 : appendStringInfoChar(buf, '\n');
353 : 296867 : }
|