1/*-------------------------------------------------------------------------
2 *
3 * xlogdesc.c
4 * rmgr descriptor routines for access/transam/xlog.c
5 *
6 * Portions Copyright (c) 1996-2019, 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 */
27const 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
36void
37xlog_desc(StringInfo buf, XLogReaderState *record)
38{
39 char *rec = XLogRecGetData(record);
40 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
41
42 if (info == XLOG_CHECKPOINT_SHUTDOWN ||
43 info == XLOG_CHECKPOINT_ONLINE)
44 {
45 CheckPoint *checkpoint = (CheckPoint *) rec;
46
47 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",
52 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
53 checkpoint->ThisTimeLineID,
54 checkpoint->PrevTimeLineID,
55 checkpoint->fullPageWrites ? "true" : "false",
56 EpochFromFullTransactionId(checkpoint->nextFullXid),
57 XidFromFullTransactionId(checkpoint->nextFullXid),
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 }
70 else if (info == XLOG_NEXTOID)
71 {
72 Oid nextOid;
73
74 memcpy(&nextOid, rec, sizeof(Oid));
75 appendStringInfo(buf, "%u", nextOid);
76 }
77 else if (info == XLOG_RESTORE_POINT)
78 {
79 xl_restore_point *xlrec = (xl_restore_point *) rec;
80
81 appendStringInfoString(buf, xlrec->rp_name);
82 }
83 else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
84 {
85 /* no further information to print */
86 }
87 else if (info == XLOG_BACKUP_END)
88 {
89 XLogRecPtr startpoint;
90
91 memcpy(&startpoint, rec, sizeof(XLogRecPtr));
92 appendStringInfo(buf, "%X/%X",
93 (uint32) (startpoint >> 32), (uint32) startpoint);
94 }
95 else if (info == XLOG_PARAMETER_CHANGE)
96 {
97 xl_parameter_change xlrec;
98 const char *wal_level_str;
99 const struct config_enum_entry *entry;
100
101 memcpy(&xlrec, rec, sizeof(xl_parameter_change));
102
103 /* Find a string representation for wal_level */
104 wal_level_str = "?";
105 for (entry = wal_level_options; entry->name; entry++)
106 {
107 if (entry->val == xlrec.wal_level)
108 {
109 wal_level_str = entry->name;
110 break;
111 }
112 }
113
114 appendStringInfo(buf, "max_connections=%d max_worker_processes=%d "
115 "max_wal_senders=%d max_prepared_xacts=%d "
116 "max_locks_per_xact=%d wal_level=%s "
117 "wal_log_hints=%s track_commit_timestamp=%s",
118 xlrec.MaxConnections,
119 xlrec.max_worker_processes,
120 xlrec.max_wal_senders,
121 xlrec.max_prepared_xacts,
122 xlrec.max_locks_per_xact,
123 wal_level_str,
124 xlrec.wal_log_hints ? "on" : "off",
125 xlrec.track_commit_timestamp ? "on" : "off");
126 }
127 else if (info == XLOG_FPW_CHANGE)
128 {
129 bool fpw;
130
131 memcpy(&fpw, rec, sizeof(bool));
132 appendStringInfoString(buf, fpw ? "true" : "false");
133 }
134 else if (info == XLOG_END_OF_RECOVERY)
135 {
136 xl_end_of_recovery xlrec;
137
138 memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
139 appendStringInfo(buf, "tli %u; prev tli %u; time %s",
140 xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
141 timestamptz_to_str(xlrec.end_time));
142 }
143}
144
145const char *
146xlog_identify(uint8 info)
147{
148 const char *id = NULL;
149
150 switch (info & ~XLR_INFO_MASK)
151 {
152 case XLOG_CHECKPOINT_SHUTDOWN:
153 id = "CHECKPOINT_SHUTDOWN";
154 break;
155 case XLOG_CHECKPOINT_ONLINE:
156 id = "CHECKPOINT_ONLINE";
157 break;
158 case XLOG_NOOP:
159 id = "NOOP";
160 break;
161 case XLOG_NEXTOID:
162 id = "NEXTOID";
163 break;
164 case XLOG_SWITCH:
165 id = "SWITCH";
166 break;
167 case XLOG_BACKUP_END:
168 id = "BACKUP_END";
169 break;
170 case XLOG_PARAMETER_CHANGE:
171 id = "PARAMETER_CHANGE";
172 break;
173 case XLOG_RESTORE_POINT:
174 id = "RESTORE_POINT";
175 break;
176 case XLOG_FPW_CHANGE:
177 id = "FPW_CHANGE";
178 break;
179 case XLOG_END_OF_RECOVERY:
180 id = "END_OF_RECOVERY";
181 break;
182 case XLOG_FPI:
183 id = "FPI";
184 break;
185 case XLOG_FPI_FOR_HINT:
186 id = "FPI_FOR_HINT";
187 break;
188 }
189
190 return id;
191}
192