Age Owner 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-2023, 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 : void
3062 heikki.linnakangas 37 CBC 76 : xlog_desc(StringInfo buf, XLogReaderState *record)
38 : {
3221 39 76 : char *rec = XLogRecGetData(record);
3062 40 76 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
41 :
3784 alvherre 42 76 : if (info == XLOG_CHECKPOINT_SHUTDOWN ||
43 : info == XLOG_CHECKPOINT_ONLINE)
44 4 : {
45 4 : CheckPoint *checkpoint = (CheckPoint *) rec;
46 :
3124 andres 47 8 : appendStringInfo(buf, "redo %X/%X; "
48 : "tli %u; prev tli %u; fpw %s; xid %u:%u; oid %u; multi %u; offset %u; "
49 : "oldest xid %u in DB %u; oldest multi %u in DB %u; "
50 : "oldest/newest commit timestamp xid: %u/%u; "
51 : "oldest running xid %u; %s",
775 peter 52 4 : LSN_FORMAT_ARGS(checkpoint->redo),
53 : checkpoint->ThisTimeLineID,
54 : checkpoint->PrevTimeLineID,
3784 alvherre 55 4 : checkpoint->fullPageWrites ? "true" : "false",
971 andres 56 4 : EpochFromFullTransactionId(checkpoint->nextXid),
57 4 : XidFromFullTransactionId(checkpoint->nextXid),
58 : checkpoint->nextOid,
59 : checkpoint->nextMulti,
60 : checkpoint->nextMultiOffset,
61 : checkpoint->oldestXid,
62 : checkpoint->oldestXidDB,
63 : checkpoint->oldestMulti,
64 : checkpoint->oldestMultiDB,
65 : checkpoint->oldestCommitTsXid,
66 : checkpoint->newestCommitTsXid,
67 : checkpoint->oldestActiveXid,
68 : (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
69 : }
3784 alvherre 70 72 : else if (info == XLOG_NEXTOID)
71 : {
72 : Oid nextOid;
73 :
74 1 : memcpy(&nextOid, rec, sizeof(Oid));
3124 andres 75 1 : appendStringInfo(buf, "%u", nextOid);
76 : }
3784 alvherre 77 71 : else if (info == XLOG_RESTORE_POINT)
78 : {
3784 alvherre 79 UBC 0 : xl_restore_point *xlrec = (xl_restore_point *) rec;
80 :
2890 peter_e 81 0 : appendStringInfoString(buf, xlrec->rp_name);
82 : }
3058 heikki.linnakangas 83 CBC 71 : else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
84 : {
85 : /* no further information to print */
86 : }
3784 alvherre 87 13 : else if (info == XLOG_BACKUP_END)
88 : {
89 : XLogRecPtr startpoint;
90 :
91 4 : memcpy(&startpoint, rec, sizeof(XLogRecPtr));
775 peter 92 4 : appendStringInfo(buf, "%X/%X", LSN_FORMAT_ARGS(startpoint));
93 : }
3784 alvherre 94 9 : else if (info == XLOG_PARAMETER_CHANGE)
95 : {
96 : xl_parameter_change xlrec;
97 : const char *wal_level_str;
98 : const struct config_enum_entry *entry;
99 :
100 7 : memcpy(&xlrec, rec, sizeof(xl_parameter_change));
101 :
102 : /* Find a string representation for wal_level */
103 7 : wal_level_str = "?";
104 12 : for (entry = wal_level_options; entry->name; entry++)
105 : {
106 12 : if (entry->val == xlrec.wal_level)
107 : {
108 7 : wal_level_str = entry->name;
109 7 : break;
110 : }
111 : }
112 :
3047 heikki.linnakangas 113 14 : appendStringInfo(buf, "max_connections=%d max_worker_processes=%d "
114 : "max_wal_senders=%d max_prepared_xacts=%d "
115 : "max_locks_per_xact=%d wal_level=%s "
116 : "wal_log_hints=%s track_commit_timestamp=%s",
117 : xlrec.MaxConnections,
118 : xlrec.max_worker_processes,
119 : xlrec.max_wal_senders,
120 : xlrec.max_prepared_xacts,
121 : xlrec.max_locks_per_xact,
122 : wal_level_str,
123 7 : xlrec.wal_log_hints ? "on" : "off",
124 7 : xlrec.track_commit_timestamp ? "on" : "off");
125 : }
3784 alvherre 126 2 : else if (info == XLOG_FPW_CHANGE)
127 : {
128 : bool fpw;
129 :
3784 alvherre 130 UBC 0 : memcpy(&fpw, rec, sizeof(bool));
2890 peter_e 131 0 : appendStringInfoString(buf, fpw ? "true" : "false");
132 : }
3722 simon 133 CBC 2 : else if (info == XLOG_END_OF_RECOVERY)
134 : {
135 : xl_end_of_recovery xlrec;
136 :
3722 simon 137 UBC 0 : memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
3124 andres 138 0 : appendStringInfo(buf, "tli %u; prev tli %u; time %s",
139 : xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
140 : timestamptz_to_str(xlrec.end_time));
141 : }
557 alvherre 142 CBC 2 : else if (info == XLOG_OVERWRITE_CONTRECORD)
143 : {
144 : xl_overwrite_contrecord xlrec;
145 :
146 1 : memcpy(&xlrec, rec, sizeof(xl_overwrite_contrecord));
147 1 : appendStringInfo(buf, "lsn %X/%X; time %s",
148 1 : LSN_FORMAT_ARGS(xlrec.overwritten_lsn),
149 : timestamptz_to_str(xlrec.overwrite_time));
150 : }
3124 andres 151 76 : }
152 :
153 : const char *
154 76 : xlog_identify(uint8 info)
155 : {
156 76 : const char *id = NULL;
157 :
3121 158 76 : switch (info & ~XLR_INFO_MASK)
159 : {
3124 160 4 : case XLOG_CHECKPOINT_SHUTDOWN:
161 4 : id = "CHECKPOINT_SHUTDOWN";
162 4 : break;
3124 andres 163 UBC 0 : case XLOG_CHECKPOINT_ONLINE:
164 0 : id = "CHECKPOINT_ONLINE";
165 0 : break;
166 0 : case XLOG_NOOP:
167 0 : id = "NOOP";
168 0 : break;
3124 andres 169 CBC 1 : case XLOG_NEXTOID:
170 1 : id = "NEXTOID";
171 1 : break;
172 1 : case XLOG_SWITCH:
173 1 : id = "SWITCH";
174 1 : break;
175 4 : case XLOG_BACKUP_END:
176 4 : id = "BACKUP_END";
177 4 : break;
178 7 : case XLOG_PARAMETER_CHANGE:
179 7 : id = "PARAMETER_CHANGE";
180 7 : break;
3124 andres 181 UBC 0 : case XLOG_RESTORE_POINT:
182 0 : id = "RESTORE_POINT";
183 0 : break;
184 0 : case XLOG_FPW_CHANGE:
185 0 : id = "FPW_CHANGE";
186 0 : break;
187 0 : case XLOG_END_OF_RECOVERY:
188 0 : id = "END_OF_RECOVERY";
189 0 : break;
557 alvherre 190 CBC 1 : case XLOG_OVERWRITE_CONTRECORD:
191 1 : id = "OVERWRITE_CONTRECORD";
192 1 : break;
3124 andres 193 48 : case XLOG_FPI:
194 48 : id = "FPI";
195 48 : break;
3058 heikki.linnakangas 196 10 : case XLOG_FPI_FOR_HINT:
197 10 : id = "FPI_FOR_HINT";
198 10 : break;
199 : }
200 :
3124 andres 201 76 : return id;
202 : }
203 :
204 : /*
205 : * Returns a string giving information about all the blocks in an
206 : * XLogRecord.
207 : */
208 : void
366 jdavis 209 34270 : XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty,
210 : bool detailed_format, StringInfo buf,
211 : uint32 *fpi_len)
212 : {
213 : int block_id;
214 :
215 34270 : Assert(record != NULL);
216 :
217 34270 : if (detailed_format && pretty)
366 jdavis 218 UBC 0 : appendStringInfoChar(buf, '\n');
219 :
366 jdavis 220 CBC 70543 : for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
221 : {
222 : RelFileLocator rlocator;
223 : ForkNumber forknum;
224 : BlockNumber blk;
225 :
363 tgl 226 36273 : if (!XLogRecGetBlockTagExtended(record, block_id,
227 : &rlocator, &forknum, &blk, NULL))
366 jdavis 228 UBC 0 : continue;
229 :
366 jdavis 230 CBC 36273 : if (detailed_format)
231 : {
232 : /* Get block references in detailed format. */
233 :
234 36273 : if (pretty)
366 jdavis 235 UBC 0 : appendStringInfoChar(buf, '\t');
366 jdavis 236 CBC 36273 : else if (block_id > 0)
237 2003 : appendStringInfoChar(buf, ' ');
238 :
239 36273 : appendStringInfo(buf,
240 : "blkref #%d: rel %u/%u/%u fork %s blk %u",
241 : block_id,
242 : rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
243 36273 : forkNames[forknum],
244 : blk);
245 :
246 36273 : if (XLogRecHasBlockImage(record, block_id))
247 : {
248 5255 : uint8 bimg_info = XLogRecGetBlock(record, block_id)->bimg_info;
249 :
250 : /* Calculate the amount of FPI data in the record. */
251 5255 : if (fpi_len)
252 5255 : *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
253 :
254 5255 : if (BKPIMAGE_COMPRESSED(bimg_info))
255 : {
256 : const char *method;
257 :
366 jdavis 258 UBC 0 : if ((bimg_info & BKPIMAGE_COMPRESS_PGLZ) != 0)
259 0 : method = "pglz";
260 0 : else if ((bimg_info & BKPIMAGE_COMPRESS_LZ4) != 0)
261 0 : method = "lz4";
262 0 : else if ((bimg_info & BKPIMAGE_COMPRESS_ZSTD) != 0)
263 0 : method = "zstd";
264 : else
265 0 : method = "unknown";
266 :
267 0 : appendStringInfo(buf,
268 : " (FPW%s); hole: offset: %u, length: %u, "
269 : "compression saved: %u, method: %s",
270 0 : XLogRecBlockImageApply(record, block_id) ?
271 : "" : " for WAL verification",
272 0 : XLogRecGetBlock(record, block_id)->hole_offset,
273 0 : XLogRecGetBlock(record, block_id)->hole_length,
274 : BLCKSZ -
275 0 : XLogRecGetBlock(record, block_id)->hole_length -
276 0 : XLogRecGetBlock(record, block_id)->bimg_len,
277 : method);
278 : }
279 : else
280 : {
366 jdavis 281 CBC 5255 : appendStringInfo(buf,
282 : " (FPW%s); hole: offset: %u, length: %u",
283 5255 : XLogRecBlockImageApply(record, block_id) ?
284 : "" : " for WAL verification",
285 5255 : XLogRecGetBlock(record, block_id)->hole_offset,
286 5255 : XLogRecGetBlock(record, block_id)->hole_length);
287 : }
288 : }
289 :
290 36273 : if (pretty)
366 jdavis 291 UBC 0 : appendStringInfoChar(buf, '\n');
292 : }
293 : else
294 : {
295 : /* Get block references in short format. */
296 :
297 0 : if (forknum != MAIN_FORKNUM)
298 : {
299 0 : appendStringInfo(buf,
300 : ", blkref #%d: rel %u/%u/%u fork %s blk %u",
301 : block_id,
302 : rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
303 0 : forkNames[forknum],
304 : blk);
305 : }
306 : else
307 : {
308 0 : appendStringInfo(buf,
309 : ", blkref #%d: rel %u/%u/%u blk %u",
310 : block_id,
311 : rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
312 : blk);
313 : }
314 :
315 0 : if (XLogRecHasBlockImage(record, block_id))
316 : {
317 : /* Calculate the amount of FPI data in the record. */
318 0 : if (fpi_len)
319 0 : *fpi_len += XLogRecGetBlock(record, block_id)->bimg_len;
320 :
321 0 : if (XLogRecBlockImageApply(record, block_id))
215 drowley 322 UNC 0 : appendStringInfoString(buf, " FPW");
323 : else
324 0 : appendStringInfoString(buf, " FPW for WAL verification");
325 : }
326 : }
327 : }
328 :
366 jdavis 329 CBC 34270 : if (!detailed_format && pretty)
366 jdavis 330 UBC 0 : appendStringInfoChar(buf, '\n');
366 jdavis 331 CBC 34270 : }
|