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 | */ |
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 |
37 | xlog_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 | |
145 | const char * |
146 | xlog_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 | |