1 /*-------------------------------------------------------------------------
2  *
3  * xlogdesc.c
4  *	  rmgr descriptor routines for access/transam/xlog.c
5  *
6  * Portions Copyright (c) 1996-2018, 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/xlog.h"
18 #include "access/xlog_internal.h"
19 #include "catalog/pg_control.h"
20 #include "utils/guc.h"
21 #include "utils/timestamp.h"
22 
23 /*
24  * GUC support
25  */
26 const struct config_enum_entry wal_level_options[] = {
27 	{"minimal", WAL_LEVEL_MINIMAL, false},
28 	{"replica", WAL_LEVEL_REPLICA, false},
29 	{"archive", WAL_LEVEL_REPLICA, true},	/* deprecated */
30 	{"hot_standby", WAL_LEVEL_REPLICA, true},	/* deprecated */
31 	{"logical", WAL_LEVEL_LOGICAL, false},
32 	{NULL, 0, false}
33 };
34 
35 void
xlog_desc(StringInfo buf,XLogReaderState * record)36 xlog_desc(StringInfo buf, XLogReaderState *record)
37 {
38 	char	   *rec = XLogRecGetData(record);
39 	uint8		info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
40 
41 	if (info == XLOG_CHECKPOINT_SHUTDOWN ||
42 		info == XLOG_CHECKPOINT_ONLINE)
43 	{
44 		CheckPoint *checkpoint = (CheckPoint *) rec;
45 
46 		appendStringInfo(buf, "redo %X/%X; "
47 						 "tli %u; prev tli %u; fpw %s; xid %u:%u; oid %u; multi %u; offset %u; "
48 						 "oldest xid %u in DB %u; oldest multi %u in DB %u; "
49 						 "oldest/newest commit timestamp xid: %u/%u; "
50 						 "oldest running xid %u; %s",
51 						 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
52 						 checkpoint->ThisTimeLineID,
53 						 checkpoint->PrevTimeLineID,
54 						 checkpoint->fullPageWrites ? "true" : "false",
55 						 checkpoint->nextXidEpoch, checkpoint->nextXid,
56 						 checkpoint->nextOid,
57 						 checkpoint->nextMulti,
58 						 checkpoint->nextMultiOffset,
59 						 checkpoint->oldestXid,
60 						 checkpoint->oldestXidDB,
61 						 checkpoint->oldestMulti,
62 						 checkpoint->oldestMultiDB,
63 						 checkpoint->oldestCommitTsXid,
64 						 checkpoint->newestCommitTsXid,
65 						 checkpoint->oldestActiveXid,
66 						 (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
67 	}
68 	else if (info == XLOG_NEXTOID)
69 	{
70 		Oid			nextOid;
71 
72 		memcpy(&nextOid, rec, sizeof(Oid));
73 		appendStringInfo(buf, "%u", nextOid);
74 	}
75 	else if (info == XLOG_RESTORE_POINT)
76 	{
77 		xl_restore_point *xlrec = (xl_restore_point *) rec;
78 
79 		appendStringInfoString(buf, xlrec->rp_name);
80 	}
81 	else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT ||
82 			 info == XLOG_FPI_MULTI)
83 	{
84 		/* no further information to print */
85 	}
86 	else if (info == XLOG_BACKUP_END)
87 	{
88 		XLogRecPtr	startpoint;
89 
90 		memcpy(&startpoint, rec, sizeof(XLogRecPtr));
91 		appendStringInfo(buf, "%X/%X",
92 						 (uint32) (startpoint >> 32), (uint32) startpoint);
93 	}
94 	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 		memcpy(&xlrec, rec, sizeof(xl_parameter_change));
101 
102 		/* Find a string representation for wal_level */
103 		wal_level_str = "?";
104 		for (entry = wal_level_options; entry->name; entry++)
105 		{
106 			if (entry->val == xlrec.wal_level)
107 			{
108 				wal_level_str = entry->name;
109 				break;
110 			}
111 		}
112 
113 		appendStringInfo(buf, "max_connections=%d max_worker_processes=%d "
114 						 "max_prepared_xacts=%d max_locks_per_xact=%d "
115 						 "wal_level=%s wal_log_hints=%s "
116 						 "track_commit_timestamp=%s",
117 						 xlrec.MaxConnections,
118 						 xlrec.max_worker_processes,
119 						 xlrec.max_prepared_xacts,
120 						 xlrec.max_locks_per_xact,
121 						 wal_level_str,
122 						 xlrec.wal_log_hints ? "on" : "off",
123 						 xlrec.track_commit_timestamp ? "on" : "off");
124 	}
125 	else if (info == XLOG_FPW_CHANGE)
126 	{
127 		bool		fpw;
128 
129 		memcpy(&fpw, rec, sizeof(bool));
130 		appendStringInfoString(buf, fpw ? "true" : "false");
131 	}
132 	else if (info == XLOG_END_OF_RECOVERY)
133 	{
134 		xl_end_of_recovery xlrec;
135 
136 		memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
137 		appendStringInfo(buf, "tli %u; prev tli %u; time %s",
138 						 xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
139 						 timestamptz_to_str(xlrec.end_time));
140 	}
141 	else if (info == XLOG_OVERWRITE_CONTRECORD)
142 	{
143 		xl_overwrite_contrecord xlrec;
144 
145 		memcpy(&xlrec, rec, sizeof(xl_overwrite_contrecord));
146 		appendStringInfo(buf, "lsn %X/%X; time %s",
147 						 (uint32) (xlrec.overwritten_lsn >> 32),
148 						 (uint32) xlrec.overwritten_lsn,
149 						 timestamptz_to_str(xlrec.overwrite_time));
150 	}
151 }
152 
153 const char *
xlog_identify(uint8 info)154 xlog_identify(uint8 info)
155 {
156 	const char *id = NULL;
157 
158 	switch (info & ~XLR_INFO_MASK)
159 	{
160 		case XLOG_CHECKPOINT_SHUTDOWN:
161 			id = "CHECKPOINT_SHUTDOWN";
162 			break;
163 		case XLOG_CHECKPOINT_ONLINE:
164 			id = "CHECKPOINT_ONLINE";
165 			break;
166 		case XLOG_NOOP:
167 			id = "NOOP";
168 			break;
169 		case XLOG_NEXTOID:
170 			id = "NEXTOID";
171 			break;
172 		case XLOG_SWITCH:
173 			id = "SWITCH";
174 			break;
175 		case XLOG_BACKUP_END:
176 			id = "BACKUP_END";
177 			break;
178 		case XLOG_PARAMETER_CHANGE:
179 			id = "PARAMETER_CHANGE";
180 			break;
181 		case XLOG_RESTORE_POINT:
182 			id = "RESTORE_POINT";
183 			break;
184 		case XLOG_FPW_CHANGE:
185 			id = "FPW_CHANGE";
186 			break;
187 		case XLOG_END_OF_RECOVERY:
188 			id = "END_OF_RECOVERY";
189 			break;
190 		case XLOG_OVERWRITE_CONTRECORD:
191 			id = "OVERWRITE_CONTRECORD";
192 			break;
193 		case XLOG_FPI:
194 			id = "FPI";
195 			break;
196 		case XLOG_FPI_FOR_HINT:
197 			id = "FPI_FOR_HINT";
198 			break;
199 		case XLOG_FPI_MULTI:
200 			id = "FPI_MULTI";
201 			break;
202 	}
203 
204 	return id;
205 }
206