Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * pg_resetwal.c
4 : : * A utility to "zero out" the xlog when it's corrupt beyond recovery.
5 : : * Can also rebuild pg_control if needed.
6 : : *
7 : : * The theory of operation is fairly simple:
8 : : * 1. Read the existing pg_control (which will include the last
9 : : * checkpoint record).
10 : : * 2. If pg_control is corrupt, attempt to intuit reasonable values,
11 : : * by scanning the old xlog if necessary.
12 : : * 3. Modify pg_control to reflect a "shutdown" state with a checkpoint
13 : : * record at the start of xlog.
14 : : * 4. Flush the existing xlog files and write a new segment with
15 : : * just a checkpoint record in it. The new segment is positioned
16 : : * just past the end of the old xlog, so that existing LSNs in
17 : : * data pages will appear to be "in the past".
18 : : * This is all pretty straightforward except for the intuition part of
19 : : * step 2 ...
20 : : *
21 : : *
22 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
23 : : * Portions Copyright (c) 1994, Regents of the University of California
24 : : *
25 : : * src/bin/pg_resetwal/pg_resetwal.c
26 : : *
27 : : *-------------------------------------------------------------------------
28 : : */
29 : :
30 : : /*
31 : : * We have to use postgres.h not postgres_fe.h here, because there's so much
32 : : * backend-only stuff in the XLOG include files we need. But we need a
33 : : * frontend-ish environment otherwise. Hence this ugly hack.
34 : : */
35 : : #define FRONTEND 1
36 : :
37 : : #include "postgres.h"
38 : :
39 : : #include <dirent.h>
40 : : #include <fcntl.h>
41 : : #include <sys/stat.h>
42 : : #include <sys/time.h>
43 : : #include <time.h>
44 : : #include <unistd.h>
45 : :
46 : : #include "access/heaptoast.h"
47 : : #include "access/multixact.h"
48 : : #include "access/transam.h"
49 : : #include "access/xlog.h"
50 : : #include "access/xlog_internal.h"
51 : : #include "common/controldata_utils.h"
52 : : #include "common/fe_memutils.h"
53 : : #include "common/file_perm.h"
54 : : #include "common/logging.h"
55 : : #include "common/restricted_token.h"
56 : : #include "common/string.h"
57 : : #include "fe_utils/option_utils.h"
58 : : #include "fe_utils/version.h"
59 : : #include "getopt_long.h"
60 : : #include "pg_getopt.h"
61 : : #include "storage/large_object.h"
62 : :
63 : : static ControlFileData ControlFile; /* pg_control values */
64 : : static XLogSegNo newXlogSegNo; /* new XLOG segment # */
65 : : static bool guessed = false; /* T if we had to guess at any values */
66 : : static const char *progname;
67 : : static uint32 set_xid_epoch = (uint32) -1;
68 : : static TransactionId set_oldest_xid = 0;
69 : : static TransactionId set_xid = 0;
70 : : static TransactionId set_oldest_commit_ts_xid = 0;
71 : : static TransactionId set_newest_commit_ts_xid = 0;
72 : : static Oid set_oid = 0;
73 : : static MultiXactId set_mxid = 0;
74 : : static MultiXactOffset set_mxoff = (MultiXactOffset) -1;
75 : : static TimeLineID minXlogTli = 0;
76 : : static XLogSegNo minXlogSegNo = 0;
77 : : static int WalSegSz;
78 : : static int set_wal_segsize;
79 : : static int set_char_signedness = -1;
80 : :
81 : : static void CheckDataVersion(void);
82 : : static bool read_controlfile(void);
83 : : static void GuessControlValues(void);
84 : : static void PrintControlValues(bool guessed);
85 : : static void PrintNewControlValues(void);
86 : : static void RewriteControlFile(void);
87 : : static void FindEndOfXLOG(void);
88 : : static void KillExistingXLOG(void);
89 : : static void KillExistingArchiveStatus(void);
90 : : static void KillExistingWALSummaries(void);
91 : : static void WriteEmptyXLOG(void);
92 : : static void usage(void);
93 : :
94 : :
95 : : int
8460 peter_e@gmx.net 96 :CBC 177 : main(int argc, char *argv[])
97 : : {
98 : : static struct option long_options[] = {
99 : : {"commit-timestamp-ids", required_argument, NULL, 'c'},
100 : : {"pgdata", required_argument, NULL, 'D'},
101 : : {"epoch", required_argument, NULL, 'e'},
102 : : {"force", no_argument, NULL, 'f'},
103 : : {"next-wal-file", required_argument, NULL, 'l'},
104 : : {"multixact-ids", required_argument, NULL, 'm'},
105 : : {"dry-run", no_argument, NULL, 'n'},
106 : : {"next-oid", required_argument, NULL, 'o'},
107 : : {"multixact-offset", required_argument, NULL, 'O'},
108 : : {"oldest-transaction-id", required_argument, NULL, 'u'},
109 : : {"next-transaction-id", required_argument, NULL, 'x'},
110 : : {"wal-segsize", required_argument, NULL, 1},
111 : : {"char-signedness", required_argument, NULL, 2},
112 : : {NULL, 0, NULL, 0}
113 : : };
114 : :
115 : : int c;
116 : 177 : bool force = false;
117 : 177 : bool noupdate = false;
4660 alvherre@alvh.no-ip. 118 : 177 : MultiXactId set_oldestmxid = 0;
119 : : char *endptr;
120 : : char *endptr2;
4050 heikki.linnakangas@i 121 : 177 : char *DataDir = NULL;
2960 andres@anarazel.de 122 : 177 : char *log_fname = NULL;
123 : : int fd;
124 : :
2401 peter@eisentraut.org 125 : 177 : pg_logging_init(argv[0]);
3182 rhaas@postgresql.org 126 : 177 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal"));
8242 bruce@momjian.us 127 : 177 : progname = get_progname(argv[0]);
128 : :
8460 peter_e@gmx.net 129 [ + + ]: 177 : if (argc > 1)
130 : : {
131 [ + + - + ]: 176 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
132 : : {
133 : 1 : usage();
134 : 1 : exit(0);
135 : : }
136 [ + + + + ]: 175 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
137 : : {
3182 rhaas@postgresql.org 138 : 45 : puts("pg_resetwal (PostgreSQL) " PG_VERSION);
8460 peter_e@gmx.net 139 : 45 : exit(0);
140 : : }
141 : : }
142 : :
143 : :
1554 bruce@momjian.us 144 [ + + ]: 293 : while ((c = getopt_long(argc, argv, "c:D:e:fl:m:no:O:u:x:", long_options, NULL)) != -1)
145 : : {
8460 peter_e@gmx.net 146 [ + + + + : 185 : switch (c)
+ + + + +
+ + + +
+ ]
147 : : {
4050 heikki.linnakangas@i 148 : 4 : case 'D':
149 : 4 : DataDir = optarg;
150 : 4 : break;
151 : :
8460 peter_e@gmx.net 152 : 35 : case 'f':
153 : 35 : force = true;
154 : 35 : break;
155 : :
156 : 38 : case 'n':
157 : 38 : noupdate = true;
158 : 38 : break;
159 : :
7007 tgl@sss.pgh.pa.us 160 : 13 : case 'e':
1529 peter@eisentraut.org 161 : 13 : errno = 0;
7007 tgl@sss.pgh.pa.us 162 : 13 : set_xid_epoch = strtoul(optarg, &endptr, 0);
1529 peter@eisentraut.org 163 [ + + + - : 13 : if (endptr == optarg || *endptr != '\0' || errno != 0)
- + ]
164 : : {
165 : : /*------
166 : : translator: the second %s is a command line argument (-e, etc) */
2401 167 : 1 : pg_log_error("invalid argument for option %s", "-e");
1298 tgl@sss.pgh.pa.us 168 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7007 169 : 1 : exit(1);
170 : : }
171 [ + + ]: 12 : if (set_xid_epoch == -1)
1298 172 : 1 : pg_fatal("transaction ID epoch (-e) must not be -1");
7007 173 : 11 : break;
174 : :
1554 bruce@momjian.us 175 : 12 : case 'u':
1529 peter@eisentraut.org 176 : 12 : errno = 0;
1554 bruce@momjian.us 177 : 12 : set_oldest_xid = strtoul(optarg, &endptr, 0);
1529 peter@eisentraut.org 178 [ + + + - : 12 : if (endptr == optarg || *endptr != '\0' || errno != 0)
- + ]
179 : : {
1554 bruce@momjian.us 180 : 1 : pg_log_error("invalid argument for option %s", "-u");
1298 tgl@sss.pgh.pa.us 181 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
1554 bruce@momjian.us 182 : 1 : exit(1);
183 : : }
184 [ + + ]: 11 : if (!TransactionIdIsNormal(set_oldest_xid))
1298 tgl@sss.pgh.pa.us 185 : 1 : pg_fatal("oldest transaction ID (-u) must be greater than or equal to %u", FirstNormalTransactionId);
1554 bruce@momjian.us 186 : 10 : break;
187 : :
8460 peter_e@gmx.net 188 : 12 : case 'x':
1529 peter@eisentraut.org 189 : 12 : errno = 0;
8426 tgl@sss.pgh.pa.us 190 : 12 : set_xid = strtoul(optarg, &endptr, 0);
1529 peter@eisentraut.org 191 [ + + + - : 12 : if (endptr == optarg || *endptr != '\0' || errno != 0)
- + ]
192 : : {
2401 193 : 1 : pg_log_error("invalid argument for option %s", "-x");
1298 tgl@sss.pgh.pa.us 194 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8426 195 : 1 : exit(1);
196 : : }
1554 bruce@momjian.us 197 [ + + ]: 11 : if (!TransactionIdIsNormal(set_xid))
1298 tgl@sss.pgh.pa.us 198 : 1 : pg_fatal("transaction ID (-x) must be greater than or equal to %u", FirstNormalTransactionId);
8460 peter_e@gmx.net 199 : 10 : break;
200 : :
3981 alvherre@alvh.no-ip. 201 : 14 : case 'c':
1529 peter@eisentraut.org 202 : 14 : errno = 0;
3591 mail@joeconway.com 203 : 14 : set_oldest_commit_ts_xid = strtoul(optarg, &endptr, 0);
1529 peter@eisentraut.org 204 [ + + + - : 14 : if (endptr == optarg || *endptr != ',' || errno != 0)
- + ]
205 : : {
2401 206 : 1 : pg_log_error("invalid argument for option %s", "-c");
1298 tgl@sss.pgh.pa.us 207 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
3981 alvherre@alvh.no-ip. 208 : 1 : exit(1);
209 : : }
3591 mail@joeconway.com 210 : 13 : set_newest_commit_ts_xid = strtoul(endptr + 1, &endptr2, 0);
1529 peter@eisentraut.org 211 [ + + + - : 13 : if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
- + ]
212 : : {
2401 213 : 1 : pg_log_error("invalid argument for option %s", "-c");
1298 tgl@sss.pgh.pa.us 214 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
3981 alvherre@alvh.no-ip. 215 : 1 : exit(1);
216 : : }
217 : :
748 peter@eisentraut.org 218 [ + + ]: 12 : if (set_oldest_commit_ts_xid < FirstNormalTransactionId &&
219 [ + - ]: 1 : set_oldest_commit_ts_xid != InvalidTransactionId)
220 : 1 : pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
221 : :
222 [ + + ]: 11 : if (set_newest_commit_ts_xid < FirstNormalTransactionId &&
223 [ + + ]: 3 : set_newest_commit_ts_xid != InvalidTransactionId)
224 : 1 : pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
3981 alvherre@alvh.no-ip. 225 : 10 : break;
226 : :
8426 tgl@sss.pgh.pa.us 227 : 12 : case 'o':
1529 peter@eisentraut.org 228 : 12 : errno = 0;
8426 tgl@sss.pgh.pa.us 229 : 12 : set_oid = strtoul(optarg, &endptr, 0);
1529 peter@eisentraut.org 230 [ + + + - : 12 : if (endptr == optarg || *endptr != '\0' || errno != 0)
- + ]
231 : : {
2401 232 : 1 : pg_log_error("invalid argument for option %s", "-o");
1298 tgl@sss.pgh.pa.us 233 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8426 234 : 1 : exit(1);
235 : : }
236 [ + + ]: 11 : if (set_oid == 0)
1298 237 : 1 : pg_fatal("OID (-o) must not be 0");
8426 238 : 10 : break;
239 : :
7487 240 : 14 : case 'm':
1529 peter@eisentraut.org 241 : 14 : errno = 0;
7487 tgl@sss.pgh.pa.us 242 : 14 : set_mxid = strtoul(optarg, &endptr, 0);
1529 peter@eisentraut.org 243 [ + + + - : 14 : if (endptr == optarg || *endptr != ',' || errno != 0)
- + ]
244 : : {
2401 245 : 1 : pg_log_error("invalid argument for option %s", "-m");
1298 tgl@sss.pgh.pa.us 246 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4660 alvherre@alvh.no-ip. 247 : 1 : exit(1);
248 : : }
249 : :
250 : 13 : set_oldestmxid = strtoul(endptr + 1, &endptr2, 0);
1529 peter@eisentraut.org 251 [ + + + - : 13 : if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
- + ]
252 : : {
2401 253 : 1 : pg_log_error("invalid argument for option %s", "-m");
1298 tgl@sss.pgh.pa.us 254 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7487 255 : 1 : exit(1);
256 : : }
257 [ + + ]: 12 : if (set_mxid == 0)
1298 258 : 1 : pg_fatal("multitransaction ID (-m) must not be 0");
259 : :
260 : : /*
261 : : * XXX It'd be nice to have more sanity checks here, e.g. so
262 : : * that oldest is not wrapped around w.r.t. nextMulti.
263 : : */
4660 alvherre@alvh.no-ip. 264 [ + + ]: 11 : if (set_oldestmxid == 0)
1298 tgl@sss.pgh.pa.us 265 : 1 : pg_fatal("oldest multitransaction ID (-m) must not be 0");
7487 266 : 10 : break;
267 : :
7446 268 : 12 : case 'O':
1529 peter@eisentraut.org 269 : 12 : errno = 0;
7446 tgl@sss.pgh.pa.us 270 : 12 : set_mxoff = strtoul(optarg, &endptr, 0);
1529 peter@eisentraut.org 271 [ + + + - : 12 : if (endptr == optarg || *endptr != '\0' || errno != 0)
- + ]
272 : : {
2401 273 : 1 : pg_log_error("invalid argument for option %s", "-O");
1298 tgl@sss.pgh.pa.us 274 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7446 275 : 1 : exit(1);
276 : : }
277 [ + + ]: 11 : if (set_mxoff == -1)
1298 278 : 1 : pg_fatal("multitransaction offset (-O) must not be -1");
7446 279 : 10 : break;
280 : :
8460 peter_e@gmx.net 281 : 11 : case 'l':
3770 fujii@postgresql.org 282 [ + + ]: 11 : if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN)
283 : : {
2401 peter@eisentraut.org 284 : 1 : pg_log_error("invalid argument for option %s", "-l");
1298 tgl@sss.pgh.pa.us 285 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8460 peter_e@gmx.net 286 : 1 : exit(1);
287 : : }
288 : :
289 : : /*
290 : : * XLogFromFileName requires wal segment size which is not yet
291 : : * set. Hence wal details are set later on.
292 : : */
2960 andres@anarazel.de 293 : 10 : log_fname = pg_strdup(optarg);
8460 peter_e@gmx.net 294 : 10 : break;
295 : :
2773 296 : 4 : case 1:
297 : : {
298 : : int wal_segsize_mb;
299 : :
791 peter@eisentraut.org 300 [ + + ]: 4 : if (!option_parse_int(optarg, "--wal-segsize", 1, 1024, &wal_segsize_mb))
301 : 1 : exit(1);
302 : 3 : set_wal_segsize = wal_segsize_mb * 1024 * 1024;
303 [ + - + + : 3 : if (!IsValidWalSegSize(set_wal_segsize))
+ - - + ]
790 dgustafsson@postgres 304 : 1 : pg_fatal("argument of %s must be a power of two between 1 and 1024", "--wal-segsize");
791 peter@eisentraut.org 305 : 2 : break;
306 : : }
307 : :
248 msawada@postgresql.o 308 : 3 : case 2:
309 : : {
310 : 3 : errno = 0;
311 : :
312 [ - + ]: 3 : if (pg_strcasecmp(optarg, "signed") == 0)
248 msawada@postgresql.o 313 :UBC 0 : set_char_signedness = 1;
248 msawada@postgresql.o 314 [ + + ]:CBC 3 : else if (pg_strcasecmp(optarg, "unsigned") == 0)
315 : 2 : set_char_signedness = 0;
316 : : else
317 : : {
318 : 1 : pg_log_error("invalid argument for option %s", "--char-signedness");
319 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
320 : 1 : exit(1);
321 : : }
322 : 2 : break;
323 : : }
324 : :
8460 peter_e@gmx.net 325 : 1 : default:
326 : : /* getopt_long already emitted a complaint */
1298 tgl@sss.pgh.pa.us 327 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8460 peter_e@gmx.net 328 : 1 : exit(1);
329 : : }
330 : : }
331 : :
4021 heikki.linnakangas@i 332 [ + + + + ]: 108 : if (DataDir == NULL && optind < argc)
333 : 103 : DataDir = argv[optind++];
334 : :
335 : : /* Complain if any arguments remain */
336 [ + + ]: 108 : if (optind < argc)
337 : : {
2401 peter@eisentraut.org 338 : 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
339 : : argv[optind]);
1298 tgl@sss.pgh.pa.us 340 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4021 heikki.linnakangas@i 341 : 1 : exit(1);
342 : : }
343 : :
344 [ + + ]: 107 : if (DataDir == NULL)
345 : : {
2401 peter@eisentraut.org 346 : 1 : pg_log_error("no data directory specified");
1298 tgl@sss.pgh.pa.us 347 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8460 peter_e@gmx.net 348 : 1 : exit(1);
349 : : }
350 : :
351 : : /*
352 : : * Don't allow pg_resetwal to be run as root, to avoid overwriting the
353 : : * ownership of files in the data directory. We need only check for root
354 : : * -- any other user won't have sufficient permissions to modify files in
355 : : * the data directory.
356 : : */
357 : : #ifndef WIN32
7622 neilc@samurai.com 358 [ - + ]: 106 : if (geteuid() == 0)
359 : : {
2401 peter@eisentraut.org 360 :UBC 0 : pg_log_error("cannot be executed by \"root\"");
1298 tgl@sss.pgh.pa.us 361 : 0 : pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
362 : : progname);
7622 neilc@samurai.com 363 : 0 : exit(1);
364 : : }
365 : : #endif
366 : :
2401 peter@eisentraut.org 367 :CBC 106 : get_restricted_token();
368 : :
369 : : /* Set mask based on PGDATA permissions */
2760 sfrost@snowman.net 370 [ + + ]: 106 : if (!GetDataDirectoryCreatePerm(DataDir))
1298 tgl@sss.pgh.pa.us 371 : 1 : pg_fatal("could not read permissions of directory \"%s\": %m",
372 : : DataDir);
373 : :
2760 sfrost@snowman.net 374 : 105 : umask(pg_mode_mask);
375 : :
759 peter@eisentraut.org 376 [ - + ]: 105 : if (chdir(DataDir) < 0)
759 peter@eisentraut.org 377 :UBC 0 : pg_fatal("could not change directory to \"%s\": %m",
378 : : DataDir);
379 : :
380 : : /* Check that data directory matches our server version */
3073 tgl@sss.pgh.pa.us 381 :CBC 105 : CheckDataVersion();
382 : :
383 : : /*
384 : : * Check for a postmaster lock file --- if there is one, refuse to
385 : : * proceed, on grounds we might be interfering with a live installation.
386 : : */
4722 387 [ + + ]: 105 : if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
388 : : {
8460 peter_e@gmx.net 389 [ - + ]: 104 : if (errno != ENOENT)
1298 tgl@sss.pgh.pa.us 390 :UBC 0 : pg_fatal("could not open file \"%s\" for reading: %m",
391 : : "postmaster.pid");
392 : : }
393 : : else
394 : : {
2401 peter@eisentraut.org 395 :CBC 1 : pg_log_error("lock file \"%s\" exists", "postmaster.pid");
1298 tgl@sss.pgh.pa.us 396 : 1 : pg_log_error_hint("Is a server running? If not, delete the lock file and try again.");
7086 bruce@momjian.us 397 : 1 : exit(1);
398 : : }
399 : :
400 : : /*
401 : : * Attempt to read the existing pg_control file
402 : : */
2079 peter@eisentraut.org 403 [ + + ]: 104 : if (!read_controlfile())
7086 bruce@momjian.us 404 : 4 : GuessControlValues();
405 : :
406 : : /*
407 : : * If no new WAL segment size was specified, use the control file value.
408 : : */
2773 peter_e@gmx.net 409 [ + + ]: 104 : if (set_wal_segsize != 0)
410 : 2 : WalSegSz = set_wal_segsize;
411 : : else
412 : 102 : WalSegSz = ControlFile.xlog_seg_size;
413 : :
2960 andres@anarazel.de 414 [ + + ]: 104 : if (log_fname != NULL)
415 : 10 : XLogFromFileName(log_fname, &minXlogTli, &minXlogSegNo, WalSegSz);
416 : :
417 : : /*
418 : : * Also look at existing segment files to set up newXlogSegNo
419 : : */
6898 tgl@sss.pgh.pa.us 420 : 104 : FindEndOfXLOG();
421 : :
422 : : /*
423 : : * If we're not going to proceed with the reset, print the current control
424 : : * file parameters.
425 : : */
4337 heikki.linnakangas@i 426 [ + + + + : 104 : if ((guessed && !force) || noupdate)
+ + ]
427 : 39 : PrintControlValues(guessed);
428 : :
429 : : /*
430 : : * Adjust fields if required by switches. (Do this now so that printout,
431 : : * if any, includes these values.)
432 : : */
7007 tgl@sss.pgh.pa.us 433 [ + + ]: 104 : if (set_xid_epoch != -1)
434 : : ControlFile.checkPointCopy.nextXid =
2405 tmunro@postgresql.or 435 : 11 : FullTransactionIdFromEpochAndXid(set_xid_epoch,
1903 andres@anarazel.de 436 : 11 : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
437 : :
1554 bruce@momjian.us 438 [ + + ]: 104 : if (set_oldest_xid != 0)
439 : : {
440 : 10 : ControlFile.checkPointCopy.oldestXid = set_oldest_xid;
441 : 10 : ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
442 : : }
443 : :
444 [ + + ]: 104 : if (set_xid != 0)
445 : : ControlFile.checkPointCopy.nextXid =
1903 andres@anarazel.de 446 : 10 : FullTransactionIdFromEpochAndXid(EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid),
447 : : set_xid);
448 : :
3591 mail@joeconway.com 449 [ + + ]: 104 : if (set_oldest_commit_ts_xid != 0)
450 : 10 : ControlFile.checkPointCopy.oldestCommitTsXid = set_oldest_commit_ts_xid;
451 [ + + ]: 104 : if (set_newest_commit_ts_xid != 0)
452 : 8 : ControlFile.checkPointCopy.newestCommitTsXid = set_newest_commit_ts_xid;
453 : :
8426 tgl@sss.pgh.pa.us 454 [ + + ]: 104 : if (set_oid != 0)
455 : 10 : ControlFile.checkPointCopy.nextOid = set_oid;
456 : :
7487 457 [ + + ]: 104 : if (set_mxid != 0)
458 : : {
459 : 10 : ControlFile.checkPointCopy.nextMulti = set_mxid;
460 : :
4660 alvherre@alvh.no-ip. 461 : 10 : ControlFile.checkPointCopy.oldestMulti = set_oldestmxid;
462 [ - + ]: 10 : if (ControlFile.checkPointCopy.oldestMulti < FirstMultiXactId)
4660 alvherre@alvh.no-ip. 463 :UBC 0 : ControlFile.checkPointCopy.oldestMulti += FirstMultiXactId;
4660 alvherre@alvh.no-ip. 464 :CBC 10 : ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
465 : : }
466 : :
7446 tgl@sss.pgh.pa.us 467 [ + + ]: 104 : if (set_mxoff != -1)
468 : 10 : ControlFile.checkPointCopy.nextMultiOffset = set_mxoff;
469 : :
7616 470 [ - + ]: 104 : if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
471 : : {
7616 tgl@sss.pgh.pa.us 472 :UBC 0 : ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
4641 heikki.linnakangas@i 473 : 0 : ControlFile.checkPointCopy.PrevTimeLineID = minXlogTli;
474 : : }
475 : :
2773 peter_e@gmx.net 476 [ + + ]:CBC 104 : if (set_wal_segsize != 0)
477 : 2 : ControlFile.xlog_seg_size = WalSegSz;
478 : :
248 msawada@postgresql.o 479 [ + + ]: 104 : if (set_char_signedness != -1)
480 : 2 : ControlFile.default_char_signedness = (set_char_signedness == 1);
481 : :
4873 heikki.linnakangas@i 482 [ + + ]: 104 : if (minXlogSegNo > newXlogSegNo)
483 : 3 : newXlogSegNo = minXlogSegNo;
484 : :
760 peter@eisentraut.org 485 [ + + ]: 104 : if (noupdate)
486 : : {
487 : 38 : PrintNewControlValues();
488 : 38 : exit(0);
489 : : }
490 : :
491 : : /*
492 : : * If we had to guess anything, and -f was not given, just print the
493 : : * guessed values and exit.
494 : : */
495 [ + + + + ]: 66 : if (guessed && !force)
496 : : {
4337 heikki.linnakangas@i 497 : 1 : PrintNewControlValues();
760 peter@eisentraut.org 498 : 1 : pg_log_error("not proceeding because control file values were guessed");
499 : 1 : pg_log_error_hint("If these values seem acceptable, use -f to force reset.");
500 : 1 : exit(1);
501 : : }
502 : :
503 : : /*
504 : : * Don't reset from a dirty pg_control without -f, either.
505 : : */
7086 bruce@momjian.us 506 [ + + + + ]: 65 : if (ControlFile.state != DB_SHUTDOWNED && !force)
507 : : {
760 peter@eisentraut.org 508 : 1 : pg_log_error("database server was not shut down cleanly");
509 : 1 : pg_log_error_detail("Resetting the write-ahead log might cause data to be lost.");
510 : 1 : pg_log_error_hint("If you want to proceed anyway, use -f to force reset.");
8460 peter_e@gmx.net 511 : 1 : exit(1);
512 : : }
513 : :
514 : : /*
515 : : * Else, do the dirty deed.
516 : : */
517 : 64 : RewriteControlFile();
518 : 64 : KillExistingXLOG();
6021 tgl@sss.pgh.pa.us 519 : 64 : KillExistingArchiveStatus();
677 rhaas@postgresql.org 520 : 64 : KillExistingWALSummaries();
8460 peter_e@gmx.net 521 : 64 : WriteEmptyXLOG();
522 : :
3090 523 : 64 : printf(_("Write-ahead log reset\n"));
8460 524 : 64 : return 0;
525 : : }
526 : :
527 : :
528 : : /*
529 : : * Look at the version string stored in PG_VERSION and decide if this utility
530 : : * can be run safely or not.
531 : : *
532 : : * We don't want to inject pg_control and WAL files that are for a different
533 : : * major version; that can't do anything good. Note that we don't treat
534 : : * mismatching version info in pg_control as a reason to bail out, because
535 : : * recovering from a corrupted pg_control is one of the main reasons for this
536 : : * program to exist at all. However, PG_VERSION is unlikely to get corrupted,
537 : : * and if it were it would be easy to fix by hand. So let's make this check
538 : : * to prevent simple user errors.
539 : : */
540 : : static void
3073 tgl@sss.pgh.pa.us 541 : 105 : CheckDataVersion(void)
542 : : {
543 : : char *version_str;
12 michael@paquier.xyz 544 :GNC 105 : uint32 version = get_pg_version(".", &version_str);
545 : :
546 [ - + ]: 105 : if (GET_PG_MAJORVERSION_NUM(version) != PG_MAJORVERSION_NUM)
547 : : {
2401 peter@eisentraut.org 548 :UBC 0 : pg_log_error("data directory is of wrong version");
1298 tgl@sss.pgh.pa.us 549 : 0 : pg_log_error_detail("File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".",
550 : : "PG_VERSION",
551 : : version_str,
552 : : PG_MAJORVERSION);
3073 553 : 0 : exit(1);
554 : : }
3073 tgl@sss.pgh.pa.us 555 :CBC 105 : }
556 : :
557 : :
558 : : /*
559 : : * Try to read the existing pg_control file.
560 : : *
561 : : * This routine is also responsible for updating old pg_control versions
562 : : * to the current format. (Currently we don't do anything of the sort.)
563 : : */
564 : : static bool
2079 peter@eisentraut.org 565 : 104 : read_controlfile(void)
566 : : {
567 : : int fd;
568 : : int len;
569 : : char *buffer;
570 : : pg_crc32c crc;
571 : :
6242 magnus@hagander.net 572 [ - + ]: 104 : if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0)
573 : : {
574 : : /*
575 : : * If pg_control is not there at all, or we can't read it, the odds
576 : : * are we've been handed a bad DataDir path, so give up. User can do
577 : : * "touch pg_control" to force us to proceed.
578 : : */
2401 peter@eisentraut.org 579 :UBC 0 : pg_log_error("could not open file \"%s\" for reading: %m",
580 : : XLOG_CONTROL_FILE);
8472 bruce@momjian.us 581 [ # # ]: 0 : if (errno == ENOENT)
1298 tgl@sss.pgh.pa.us 582 : 0 : pg_log_error_hint("If you are sure the data directory path is correct, execute\n"
583 : : " touch %s\n"
584 : : "and try again.",
585 : : XLOG_CONTROL_FILE);
8472 bruce@momjian.us 586 : 0 : exit(1);
587 : : }
588 : :
589 : : /* Use malloc to ensure we have a maxaligned buffer */
3022 tgl@sss.pgh.pa.us 590 :CBC 104 : buffer = (char *) pg_malloc(PG_CONTROL_FILE_SIZE);
591 : :
592 : 104 : len = read(fd, buffer, PG_CONTROL_FILE_SIZE);
8472 bruce@momjian.us 593 [ - + ]: 104 : if (len < 0)
1298 tgl@sss.pgh.pa.us 594 :UBC 0 : pg_fatal("could not read file \"%s\": %m", XLOG_CONTROL_FILE);
8472 bruce@momjian.us 595 :CBC 104 : close(fd);
596 : :
597 [ + - ]: 104 : if (len >= sizeof(ControlFileData) &&
3050 tgl@sss.pgh.pa.us 598 [ + + ]: 104 : ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
599 : : {
600 : : /* Check the CRC. */
4010 heikki.linnakangas@i 601 : 103 : INIT_CRC32C(crc);
602 : 103 : COMP_CRC32C(crc,
603 : : buffer,
604 : : offsetof(ControlFileData, crc));
605 : 103 : FIN_CRC32C(crc);
606 : :
2960 andres@anarazel.de 607 [ + + ]: 103 : if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
608 : : {
609 : : /* We will use the data but treat it as guessed. */
2401 peter@eisentraut.org 610 : 3 : pg_log_warning("pg_control exists but has invalid CRC; proceed with caution");
2960 andres@anarazel.de 611 : 3 : guessed = true;
612 : : }
613 : :
8472 bruce@momjian.us 614 : 103 : memcpy(&ControlFile, buffer, sizeof(ControlFile));
615 : :
616 : : /* return false if WAL segment size is not valid */
2773 peter_e@gmx.net 617 [ + + + - : 103 : if (!IsValidWalSegSize(ControlFile.xlog_seg_size))
+ - - + ]
618 : : {
2401 peter@eisentraut.org 619 : 3 : pg_log_warning(ngettext("pg_control specifies invalid WAL segment size (%d byte); proceed with caution",
620 : : "pg_control specifies invalid WAL segment size (%d bytes); proceed with caution",
621 : : ControlFile.xlog_seg_size),
622 : : ControlFile.xlog_seg_size);
2775 peter_e@gmx.net 623 : 3 : return false;
624 : : }
625 : :
8472 bruce@momjian.us 626 : 100 : return true;
627 : : }
628 : :
629 : : /* Looks like it's a mess. */
2401 peter@eisentraut.org 630 : 1 : pg_log_warning("pg_control exists but is broken or wrong version; ignoring it");
8472 bruce@momjian.us 631 : 1 : return false;
632 : : }
633 : :
634 : :
635 : : /*
636 : : * Guess at pg_control values when we can't read the old ones.
637 : : */
638 : : static void
7086 639 : 4 : GuessControlValues(void)
640 : : {
641 : : uint64 sysidentifier;
642 : : struct timeval tv;
643 : :
644 : : /*
645 : : * Set up a completely default set of pg_control values.
646 : : */
647 : 4 : guessed = true;
8472 648 : 4 : memset(&ControlFile, 0, sizeof(ControlFile));
649 : :
650 : 4 : ControlFile.pg_control_version = PG_CONTROL_VERSION;
651 : 4 : ControlFile.catalog_version_no = CATALOG_VERSION_NO;
652 : :
653 : : /*
654 : : * Create a new unique installation identifier, since we can no longer use
655 : : * any old XLOG records. See notes in xlog.c about the algorithm.
656 : : */
7086 657 : 4 : gettimeofday(&tv, NULL);
658 : 4 : sysidentifier = ((uint64) tv.tv_sec) << 32;
4171 tgl@sss.pgh.pa.us 659 : 4 : sysidentifier |= ((uint64) tv.tv_usec) << 12;
660 : 4 : sysidentifier |= getpid() & 0xFFF;
661 : :
7086 bruce@momjian.us 662 : 4 : ControlFile.system_identifier = sysidentifier;
663 : :
4873 heikki.linnakangas@i 664 : 4 : ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
7086 bruce@momjian.us 665 : 4 : ControlFile.checkPointCopy.ThisTimeLineID = 1;
4641 heikki.linnakangas@i 666 : 4 : ControlFile.checkPointCopy.PrevTimeLineID = 1;
5024 simon@2ndQuadrant.co 667 : 4 : ControlFile.checkPointCopy.fullPageWrites = false;
668 : : ControlFile.checkPointCopy.nextXid =
2405 tmunro@postgresql.or 669 : 4 : FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId);
1565 tgl@sss.pgh.pa.us 670 : 4 : ControlFile.checkPointCopy.nextOid = FirstGenbkiObjectId;
7086 bruce@momjian.us 671 : 4 : ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
672 : 4 : ControlFile.checkPointCopy.nextMultiOffset = 0;
5901 tgl@sss.pgh.pa.us 673 : 4 : ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
674 : 4 : ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
4660 alvherre@alvh.no-ip. 675 : 4 : ControlFile.checkPointCopy.oldestMulti = FirstMultiXactId;
676 : 4 : ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
6462 tgl@sss.pgh.pa.us 677 : 4 : ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
5661 678 : 4 : ControlFile.checkPointCopy.oldestActiveXid = InvalidTransactionId;
679 : :
7086 bruce@momjian.us 680 : 4 : ControlFile.state = DB_SHUTDOWNED;
6462 tgl@sss.pgh.pa.us 681 : 4 : ControlFile.time = (pg_time_t) time(NULL);
7086 bruce@momjian.us 682 : 4 : ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
2192 michael@paquier.xyz 683 : 4 : ControlFile.unloggedLSN = FirstNormalUnloggedLSN;
684 : :
685 : : /* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
686 : :
5661 tgl@sss.pgh.pa.us 687 : 4 : ControlFile.wal_level = WAL_LEVEL_MINIMAL;
4328 fujii@postgresql.org 688 : 4 : ControlFile.wal_log_hints = false;
3981 alvherre@alvh.no-ip. 689 : 4 : ControlFile.track_commit_timestamp = false;
5661 tgl@sss.pgh.pa.us 690 : 4 : ControlFile.MaxConnections = 100;
2449 michael@paquier.xyz 691 : 4 : ControlFile.max_wal_senders = 10;
3248 rhaas@postgresql.org 692 : 4 : ControlFile.max_worker_processes = 8;
5661 tgl@sss.pgh.pa.us 693 : 4 : ControlFile.max_prepared_xacts = 0;
694 : 4 : ControlFile.max_locks_per_xact = 64;
695 : :
7329 696 : 4 : ControlFile.maxAlign = MAXIMUM_ALIGNOF;
697 : 4 : ControlFile.floatFormat = FLOATFORMAT_VALUE;
8472 bruce@momjian.us 698 : 4 : ControlFile.blcksz = BLCKSZ;
699 : 4 : ControlFile.relseg_size = RELSEG_SIZE;
2773 peter_e@gmx.net 700 : 4 : ControlFile.xlog_blcksz = XLOG_BLCKSZ;
701 : 4 : ControlFile.xlog_seg_size = DEFAULT_XLOG_SEG_SIZE;
8426 tgl@sss.pgh.pa.us 702 : 4 : ControlFile.nameDataLen = NAMEDATALEN;
7517 703 : 4 : ControlFile.indexMaxKeys = INDEX_MAX_KEYS;
6782 704 : 4 : ControlFile.toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
4162 705 : 4 : ControlFile.loblksize = LOBLKSIZE;
75 tgl@sss.pgh.pa.us 706 :GNC 4 : ControlFile.float8ByVal = true; /* vestigial */
707 : :
708 : : /*
709 : : * XXX eventually, should try to grovel through old XLOG to develop more
710 : : * accurate values for TimeLineID, nextXID, etc.
711 : : */
8472 bruce@momjian.us 712 :CBC 4 : }
713 : :
714 : :
715 : : /*
716 : : * Print the guessed pg_control values when we had to guess.
717 : : *
718 : : * NB: this display should be just those fields that will not be
719 : : * reset by RewriteControlFile().
720 : : */
721 : : static void
7086 722 : 39 : PrintControlValues(bool guessed)
723 : : {
724 [ + + ]: 39 : if (guessed)
725 : 3 : printf(_("Guessed pg_control values:\n\n"));
726 : : else
4337 heikki.linnakangas@i 727 : 36 : printf(_("Current pg_control values:\n\n"));
728 : :
7007 tgl@sss.pgh.pa.us 729 : 39 : printf(_("pg_control version number: %u\n"),
730 : : ControlFile.pg_control_version);
731 : 39 : printf(_("Catalog version number: %u\n"),
732 : : ControlFile.catalog_version_no);
212 peter@eisentraut.org 733 : 39 : printf(_("Database system identifier: %" PRIu64 "\n"),
734 : : ControlFile.system_identifier);
7007 tgl@sss.pgh.pa.us 735 : 39 : printf(_("Latest checkpoint's TimeLineID: %u\n"),
736 : : ControlFile.checkPointCopy.ThisTimeLineID);
4890 peter_e@gmx.net 737 [ + + ]: 39 : printf(_("Latest checkpoint's full_page_writes: %s\n"),
738 : : ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
3545 mail@joeconway.com 739 : 39 : printf(_("Latest checkpoint's NextXID: %u:%u\n"),
740 : : EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid),
741 : : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
7007 tgl@sss.pgh.pa.us 742 : 39 : printf(_("Latest checkpoint's NextOID: %u\n"),
743 : : ControlFile.checkPointCopy.nextOid);
744 : 39 : printf(_("Latest checkpoint's NextMultiXactId: %u\n"),
745 : : ControlFile.checkPointCopy.nextMulti);
746 : 39 : printf(_("Latest checkpoint's NextMultiOffset: %u\n"),
747 : : ControlFile.checkPointCopy.nextMultiOffset);
5901 748 : 39 : printf(_("Latest checkpoint's oldestXID: %u\n"),
749 : : ControlFile.checkPointCopy.oldestXid);
750 : 39 : printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
751 : : ControlFile.checkPointCopy.oldestXidDB);
5661 752 : 39 : printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
753 : : ControlFile.checkPointCopy.oldestActiveXid);
4660 alvherre@alvh.no-ip. 754 : 39 : printf(_("Latest checkpoint's oldestMultiXid: %u\n"),
755 : : ControlFile.checkPointCopy.oldestMulti);
756 : 39 : printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
757 : : ControlFile.checkPointCopy.oldestMultiDB);
3591 mail@joeconway.com 758 : 39 : printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
759 : : ControlFile.checkPointCopy.oldestCommitTsXid);
760 : 39 : printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
761 : : ControlFile.checkPointCopy.newestCommitTsXid);
7007 tgl@sss.pgh.pa.us 762 : 39 : printf(_("Maximum data alignment: %u\n"),
763 : : ControlFile.maxAlign);
764 : : /* we don't print floatFormat since can't say much useful about it */
765 : 39 : printf(_("Database block size: %u\n"),
766 : : ControlFile.blcksz);
767 : 39 : printf(_("Blocks per segment of large relation: %u\n"),
768 : : ControlFile.relseg_size);
769 : 39 : printf(_("WAL block size: %u\n"),
770 : : ControlFile.xlog_blcksz);
771 : 39 : printf(_("Bytes per WAL segment: %u\n"),
772 : : ControlFile.xlog_seg_size);
773 : 39 : printf(_("Maximum length of identifiers: %u\n"),
774 : : ControlFile.nameDataLen);
775 : 39 : printf(_("Maximum columns in an index: %u\n"),
776 : : ControlFile.indexMaxKeys);
6782 777 : 39 : printf(_("Maximum size of a TOAST chunk: %u\n"),
778 : : ControlFile.toast_max_chunk_size);
4162 779 : 39 : printf(_("Size of a large-object chunk: %u\n"),
780 : : ControlFile.loblksize);
781 : : /* This is no longer configurable, but users may still expect to see it: */
8426 782 : 39 : printf(_("Date/time type storage: %s\n"),
783 : : _("64-bit integers"));
6398 784 [ + - ]: 39 : printf(_("Float8 argument passing: %s\n"),
785 : : (ControlFile.float8ByVal ? _("by value") : _("by reference")));
4563 simon@2ndQuadrant.co 786 : 39 : printf(_("Data page checksum version: %u\n"),
787 : : ControlFile.data_checksum_version);
248 msawada@postgresql.o 788 [ + + ]: 39 : printf(_("Default char data signedness: %s\n"),
789 : : (ControlFile.default_char_signedness ? _("signed") : _("unsigned")));
8472 bruce@momjian.us 790 : 39 : }
791 : :
792 : :
793 : : /*
794 : : * Print the values to be changed.
795 : : */
796 : : static void
3726 andres@anarazel.de 797 : 39 : PrintNewControlValues(void)
798 : : {
799 : : char fname[MAXFNAMELEN];
800 : :
801 : : /* This will be always printed in order to keep format same. */
4337 heikki.linnakangas@i 802 : 39 : printf(_("\n\nValues to be changed:\n\n"));
803 : :
2960 andres@anarazel.de 804 : 39 : XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID,
805 : : newXlogSegNo, WalSegSz);
1138 tgl@sss.pgh.pa.us 806 : 39 : printf(_("First log segment after reset: %s\n"), fname);
807 : :
4337 heikki.linnakangas@i 808 [ + + ]: 39 : if (set_mxid != 0)
809 : : {
810 : 1 : printf(_("NextMultiXactId: %u\n"),
811 : : ControlFile.checkPointCopy.nextMulti);
812 : 1 : printf(_("OldestMultiXid: %u\n"),
813 : : ControlFile.checkPointCopy.oldestMulti);
814 : 1 : printf(_("OldestMulti's DB: %u\n"),
815 : : ControlFile.checkPointCopy.oldestMultiDB);
816 : : }
817 : :
818 [ + + ]: 39 : if (set_mxoff != -1)
819 : : {
820 : 1 : printf(_("NextMultiOffset: %u\n"),
821 : : ControlFile.checkPointCopy.nextMultiOffset);
822 : : }
823 : :
824 [ + + ]: 39 : if (set_oid != 0)
825 : : {
826 : 1 : printf(_("NextOID: %u\n"),
827 : : ControlFile.checkPointCopy.nextOid);
828 : : }
829 : :
830 [ + + ]: 39 : if (set_xid != 0)
831 : : {
832 : 1 : printf(_("NextXID: %u\n"),
833 : : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
834 : 1 : printf(_("OldestXID: %u\n"),
835 : : ControlFile.checkPointCopy.oldestXid);
836 : 1 : printf(_("OldestXID's DB: %u\n"),
837 : : ControlFile.checkPointCopy.oldestXidDB);
838 : : }
839 : :
840 [ + + ]: 39 : if (set_xid_epoch != -1)
841 : : {
4097 peter_e@gmx.net 842 : 1 : printf(_("NextXID epoch: %u\n"),
843 : : EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
844 : : }
845 : :
3591 mail@joeconway.com 846 [ + + ]: 39 : if (set_oldest_commit_ts_xid != 0)
847 : : {
848 : 1 : printf(_("oldestCommitTsXid: %u\n"),
849 : : ControlFile.checkPointCopy.oldestCommitTsXid);
850 : : }
851 [ - + ]: 39 : if (set_newest_commit_ts_xid != 0)
852 : : {
3591 mail@joeconway.com 853 :UBC 0 : printf(_("newestCommitTsXid: %u\n"),
854 : : ControlFile.checkPointCopy.newestCommitTsXid);
855 : : }
856 : :
2773 peter_e@gmx.net 857 [ + + ]:CBC 39 : if (set_wal_segsize != 0)
858 : : {
859 : 1 : printf(_("Bytes per WAL segment: %u\n"),
860 : : ControlFile.xlog_seg_size);
861 : : }
4337 heikki.linnakangas@i 862 : 39 : }
863 : :
864 : :
865 : : /*
866 : : * Write out the new pg_control file.
867 : : */
868 : : static void
7086 bruce@momjian.us 869 : 64 : RewriteControlFile(void)
870 : : {
871 : : /*
872 : : * Adjust fields as needed to force an empty XLOG starting at
873 : : * newXlogSegNo.
874 : : */
2667 alvherre@alvh.no-ip. 875 : 64 : XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD, WalSegSz,
876 : : ControlFile.checkPointCopy.redo);
6462 tgl@sss.pgh.pa.us 877 : 64 : ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
878 : :
8472 bruce@momjian.us 879 : 64 : ControlFile.state = DB_SHUTDOWNED;
880 : 64 : ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
4873 heikki.linnakangas@i 881 : 64 : ControlFile.minRecoveryPoint = 0;
4710 882 : 64 : ControlFile.minRecoveryPointTLI = 0;
4873 883 : 64 : ControlFile.backupStartPoint = 0;
884 : 64 : ControlFile.backupEndPoint = 0;
5185 885 : 64 : ControlFile.backupEndRequired = false;
886 : :
887 : : /*
888 : : * Force the defaults for max_* settings. The values don't really matter
889 : : * as long as wal_level='minimal'; the postmaster will reset these fields
890 : : * anyway at startup.
891 : : */
5661 tgl@sss.pgh.pa.us 892 : 64 : ControlFile.wal_level = WAL_LEVEL_MINIMAL;
4328 fujii@postgresql.org 893 : 64 : ControlFile.wal_log_hints = false;
3981 alvherre@alvh.no-ip. 894 : 64 : ControlFile.track_commit_timestamp = false;
5661 heikki.linnakangas@i 895 : 64 : ControlFile.MaxConnections = 100;
2449 michael@paquier.xyz 896 : 64 : ControlFile.max_wal_senders = 10;
3248 rhaas@postgresql.org 897 : 64 : ControlFile.max_worker_processes = 8;
5661 heikki.linnakangas@i 898 : 64 : ControlFile.max_prepared_xacts = 0;
899 : 64 : ControlFile.max_locks_per_xact = 64;
900 : :
901 : : /* The control file gets flushed here. */
2401 peter@eisentraut.org 902 : 64 : update_controlfile(".", &ControlFile, true);
8472 bruce@momjian.us 903 : 64 : }
904 : :
905 : :
906 : : /*
907 : : * Scan existing XLOG files and determine the highest existing WAL address
908 : : *
909 : : * On entry, ControlFile.checkPointCopy.redo and ControlFile.xlog_seg_size
910 : : * are assumed valid (note that we allow the old xlog seg size to differ
911 : : * from what we're using). On exit, newXlogSegNo is set to suitable
912 : : * value for the beginning of replacement WAL (in our seg size).
913 : : */
914 : : static void
6898 tgl@sss.pgh.pa.us 915 : 104 : FindEndOfXLOG(void)
916 : : {
917 : : DIR *xldir;
918 : : struct dirent *xlde;
919 : : uint64 xlogbytepos;
920 : :
921 : : /*
922 : : * Initialize the max() computation using the last checkpoint address from
923 : : * old pg_control. Note that for the moment we are working with segment
924 : : * numbering according to the old xlog seg size.
925 : : */
1118 michael@paquier.xyz 926 : 104 : XLByteToSeg(ControlFile.checkPointCopy.redo, newXlogSegNo,
927 : : ControlFile.xlog_seg_size);
928 : :
929 : : /*
930 : : * Scan the pg_wal directory to find existing WAL segment files. We assume
931 : : * any present have been used; in most scenarios this should be
932 : : * conservative, because of xlog.c's attempts to pre-create files.
933 : : */
6898 tgl@sss.pgh.pa.us 934 : 104 : xldir = opendir(XLOGDIR);
935 [ - + ]: 104 : if (xldir == NULL)
1298 tgl@sss.pgh.pa.us 936 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
937 : :
4238 bruce@momjian.us 938 [ + + ]:CBC 796 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
939 : : {
3769 fujii@postgresql.org 940 [ + + - + ]: 1109 : if (IsXLogFileName(xlde->d_name) ||
941 : 417 : IsPartialXLogFileName(xlde->d_name))
942 : : {
943 : : TimeLineID tli;
944 : : XLogSegNo segno;
945 : :
946 : : /* Use the segment size from the control file */
1118 michael@paquier.xyz 947 : 275 : XLogFromFileName(xlde->d_name, &tli, &segno,
948 : 275 : ControlFile.xlog_seg_size);
949 : :
950 : : /*
951 : : * Note: we take the max of all files found, regardless of their
952 : : * timelines. Another possibility would be to ignore files of
953 : : * timelines other than the target TLI, but this seems safer.
954 : : * Better too large a result than too small...
955 : : */
4873 heikki.linnakangas@i 956 [ + + ]: 275 : if (segno > newXlogSegNo)
957 : 24 : newXlogSegNo = segno;
958 : : }
959 : : }
960 : :
6898 tgl@sss.pgh.pa.us 961 [ - + ]: 104 : if (errno)
1298 tgl@sss.pgh.pa.us 962 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
963 : :
4238 bruce@momjian.us 964 [ - + ]:CBC 104 : if (closedir(xldir))
1298 tgl@sss.pgh.pa.us 965 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
966 : :
967 : : /*
968 : : * Finally, convert to new xlog seg size, and advance by one to ensure we
969 : : * are in virgin territory.
970 : : */
4873 heikki.linnakangas@i 971 :CBC 104 : xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
2773 peter_e@gmx.net 972 : 104 : newXlogSegNo = (xlogbytepos + ControlFile.xlog_seg_size - 1) / WalSegSz;
4873 heikki.linnakangas@i 973 : 104 : newXlogSegNo++;
6898 tgl@sss.pgh.pa.us 974 : 104 : }
975 : :
976 : :
977 : : /*
978 : : * Remove existing XLOG files
979 : : */
980 : : static void
8472 bruce@momjian.us 981 : 64 : KillExistingXLOG(void)
982 : : {
983 : : DIR *xldir;
984 : : struct dirent *xlde;
985 : : char path[MAXPGPATH + sizeof(XLOGDIR)];
986 : :
7420 tgl@sss.pgh.pa.us 987 : 64 : xldir = opendir(XLOGDIR);
8472 bruce@momjian.us 988 [ - + ]: 64 : if (xldir == NULL)
1298 tgl@sss.pgh.pa.us 989 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
990 : :
4238 bruce@momjian.us 991 [ + + ]:CBC 407 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
992 : : {
3769 fujii@postgresql.org 993 [ + + - + ]: 600 : if (IsXLogFileName(xlde->d_name) ||
994 : 257 : IsPartialXLogFileName(xlde->d_name))
995 : : {
3121 peter_e@gmx.net 996 : 86 : snprintf(path, sizeof(path), "%s/%s", XLOGDIR, xlde->d_name);
8472 bruce@momjian.us 997 [ - + ]: 86 : if (unlink(path) < 0)
1298 tgl@sss.pgh.pa.us 998 :UBC 0 : pg_fatal("could not delete file \"%s\": %m", path);
999 : : }
1000 : : }
1001 : :
8472 bruce@momjian.us 1002 [ - + ]:CBC 64 : if (errno)
1298 tgl@sss.pgh.pa.us 1003 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
1004 : :
4238 bruce@momjian.us 1005 [ - + ]:CBC 64 : if (closedir(xldir))
1298 tgl@sss.pgh.pa.us 1006 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
8472 bruce@momjian.us 1007 :CBC 64 : }
1008 : :
1009 : :
1010 : : /*
1011 : : * Remove existing archive status files
1012 : : */
1013 : : static void
6021 tgl@sss.pgh.pa.us 1014 : 64 : KillExistingArchiveStatus(void)
1015 : : {
1016 : : #define ARCHSTATDIR XLOGDIR "/archive_status"
1017 : :
1018 : : DIR *xldir;
1019 : : struct dirent *xlde;
1020 : : char path[MAXPGPATH + sizeof(ARCHSTATDIR)];
1021 : :
1022 : 64 : xldir = opendir(ARCHSTATDIR);
1023 [ - + ]: 64 : if (xldir == NULL)
1298 tgl@sss.pgh.pa.us 1024 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", ARCHSTATDIR);
1025 : :
4238 bruce@momjian.us 1026 [ + + ]:CBC 192 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1027 : : {
3770 fujii@postgresql.org 1028 [ - + ]: 128 : if (strspn(xlde->d_name, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
3770 fujii@postgresql.org 1029 [ # # ]:UBC 0 : (strcmp(xlde->d_name + XLOG_FNAME_LEN, ".ready") == 0 ||
3769 1030 [ # # ]: 0 : strcmp(xlde->d_name + XLOG_FNAME_LEN, ".done") == 0 ||
1031 [ # # ]: 0 : strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.ready") == 0 ||
1032 [ # # ]: 0 : strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.done") == 0))
1033 : : {
3121 peter_e@gmx.net 1034 : 0 : snprintf(path, sizeof(path), "%s/%s", ARCHSTATDIR, xlde->d_name);
6021 tgl@sss.pgh.pa.us 1035 [ # # ]: 0 : if (unlink(path) < 0)
1298 1036 : 0 : pg_fatal("could not delete file \"%s\": %m", path);
1037 : : }
1038 : : }
1039 : :
6021 tgl@sss.pgh.pa.us 1040 [ - + ]:CBC 64 : if (errno)
1298 tgl@sss.pgh.pa.us 1041 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", ARCHSTATDIR);
1042 : :
4238 bruce@momjian.us 1043 [ - + ]:CBC 64 : if (closedir(xldir))
1298 tgl@sss.pgh.pa.us 1044 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
6021 tgl@sss.pgh.pa.us 1045 :CBC 64 : }
1046 : :
1047 : : /*
1048 : : * Remove existing WAL summary files
1049 : : */
1050 : : static void
677 rhaas@postgresql.org 1051 : 64 : KillExistingWALSummaries(void)
1052 : : {
1053 : : #define WALSUMMARYDIR XLOGDIR "/summaries"
1054 : : #define WALSUMMARY_NHEXCHARS 40
1055 : :
1056 : : DIR *xldir;
1057 : : struct dirent *xlde;
1058 : : char path[MAXPGPATH + sizeof(WALSUMMARYDIR)];
1059 : :
1060 : 64 : xldir = opendir(WALSUMMARYDIR);
1061 [ - + ]: 64 : if (xldir == NULL)
677 rhaas@postgresql.org 1062 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", WALSUMMARYDIR);
1063 : :
677 rhaas@postgresql.org 1064 [ + + ]:CBC 192 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1065 : : {
1066 [ - + ]: 128 : if (strspn(xlde->d_name, "0123456789ABCDEF") == WALSUMMARY_NHEXCHARS &&
677 rhaas@postgresql.org 1067 [ # # ]:UBC 0 : strcmp(xlde->d_name + WALSUMMARY_NHEXCHARS, ".summary") == 0)
1068 : : {
1069 : 0 : snprintf(path, sizeof(path), "%s/%s", WALSUMMARYDIR, xlde->d_name);
1070 [ # # ]: 0 : if (unlink(path) < 0)
1071 : 0 : pg_fatal("could not delete file \"%s\": %m", path);
1072 : : }
1073 : : }
1074 : :
677 rhaas@postgresql.org 1075 [ - + ]:CBC 64 : if (errno)
677 rhaas@postgresql.org 1076 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", WALSUMMARYDIR);
1077 : :
677 rhaas@postgresql.org 1078 [ - + ]:CBC 64 : if (closedir(xldir))
677 rhaas@postgresql.org 1079 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
677 rhaas@postgresql.org 1080 :CBC 64 : }
1081 : :
1082 : : /*
1083 : : * Write an empty XLOG file, containing only the checkpoint record
1084 : : * already set up in ControlFile.
1085 : : */
1086 : : static void
8472 bruce@momjian.us 1087 : 64 : WriteEmptyXLOG(void)
1088 : : {
1089 : : PGAlignedXLogBlock buffer;
1090 : : XLogPageHeader page;
1091 : : XLogLongPageHeader longpage;
1092 : : XLogRecord *record;
1093 : : pg_crc32c crc;
1094 : : char path[MAXPGPATH];
1095 : : int fd;
1096 : : int nbytes;
1097 : : char *recptr;
1098 : :
2613 tgl@sss.pgh.pa.us 1099 : 64 : memset(buffer.data, 0, XLOG_BLCKSZ);
1100 : :
1101 : : /* Set up the XLOG page header */
1102 : 64 : page = (XLogPageHeader) buffer.data;
8472 bruce@momjian.us 1103 : 64 : page->xlp_magic = XLOG_PAGE_MAGIC;
7768 tgl@sss.pgh.pa.us 1104 : 64 : page->xlp_info = XLP_LONG_HEADER;
1105 : 64 : page->xlp_tli = ControlFile.checkPointCopy.ThisTimeLineID;
4873 heikki.linnakangas@i 1106 : 64 : page->xlp_pageaddr = ControlFile.checkPointCopy.redo - SizeOfXLogLongPHD;
7768 tgl@sss.pgh.pa.us 1107 : 64 : longpage = (XLogLongPageHeader) page;
1108 : 64 : longpage->xlp_sysid = ControlFile.system_identifier;
2960 andres@anarazel.de 1109 : 64 : longpage->xlp_seg_size = WalSegSz;
7145 tgl@sss.pgh.pa.us 1110 : 64 : longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
1111 : :
1112 : : /* Insert the initial checkpoint record */
3994 heikki.linnakangas@i 1113 : 64 : recptr = (char *) page + SizeOfXLogLongPHD;
1114 : 64 : record = (XLogRecord *) recptr;
4873 1115 : 64 : record->xl_prev = 0;
7929 tgl@sss.pgh.pa.us 1116 : 64 : record->xl_xid = InvalidTransactionId;
3994 heikki.linnakangas@i 1117 : 64 : record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
8472 bruce@momjian.us 1118 : 64 : record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
1119 : 64 : record->xl_rmid = RM_XLOG_ID;
1120 : :
3994 heikki.linnakangas@i 1121 : 64 : recptr += SizeOfXLogRecord;
3135 tgl@sss.pgh.pa.us 1122 : 64 : *(recptr++) = (char) XLR_BLOCK_ID_DATA_SHORT;
3994 heikki.linnakangas@i 1123 : 64 : *(recptr++) = sizeof(CheckPoint);
1124 : 64 : memcpy(recptr, &ControlFile.checkPointCopy,
1125 : : sizeof(CheckPoint));
1126 : :
4010 1127 : 64 : INIT_CRC32C(crc);
3994 1128 : 64 : COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
4010 1129 : 64 : COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
1130 : 64 : FIN_CRC32C(crc);
8472 bruce@momjian.us 1131 : 64 : record->xl_crc = crc;
1132 : :
1133 : : /* Write the first page */
2960 andres@anarazel.de 1134 : 64 : XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID,
1135 : : newXlogSegNo, WalSegSz);
1136 : :
8472 bruce@momjian.us 1137 : 64 : unlink(path);
1138 : :
1139 : 64 : fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
1140 : : pg_file_create_mode);
1141 [ - + ]: 64 : if (fd < 0)
1298 tgl@sss.pgh.pa.us 1142 :UBC 0 : pg_fatal("could not open file \"%s\": %m", path);
1143 : :
8472 bruce@momjian.us 1144 :CBC 64 : errno = 0;
2613 tgl@sss.pgh.pa.us 1145 [ - + ]: 64 : if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1146 : : {
1147 : : /* if write didn't set errno, assume problem is no disk space */
8472 bruce@momjian.us 1148 [ # # ]:UBC 0 : if (errno == 0)
1149 : 0 : errno = ENOSPC;
1298 tgl@sss.pgh.pa.us 1150 : 0 : pg_fatal("could not write file \"%s\": %m", path);
1151 : : }
1152 : :
1153 : : /* Fill the rest of the file with zeroes */
2613 tgl@sss.pgh.pa.us 1154 :CBC 64 : memset(buffer.data, 0, XLOG_BLCKSZ);
2960 andres@anarazel.de 1155 [ + + ]: 115712 : for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ)
1156 : : {
8472 bruce@momjian.us 1157 : 115648 : errno = 0;
2613 tgl@sss.pgh.pa.us 1158 [ - + ]: 115648 : if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1159 : : {
8472 bruce@momjian.us 1160 [ # # ]:UBC 0 : if (errno == 0)
1161 : 0 : errno = ENOSPC;
1298 tgl@sss.pgh.pa.us 1162 : 0 : pg_fatal("could not write file \"%s\": %m", path);
1163 : : }
1164 : : }
1165 : :
8472 bruce@momjian.us 1166 [ - + ]:CBC 64 : if (fsync(fd) != 0)
1298 tgl@sss.pgh.pa.us 1167 :UBC 0 : pg_fatal("fsync error: %m");
1168 : :
8472 bruce@momjian.us 1169 :CBC 64 : close(fd);
1170 : 64 : }
1171 : :
1172 : :
1173 : : static void
1174 : 1 : usage(void)
1175 : : {
3090 peter_e@gmx.net 1176 : 1 : printf(_("%s resets the PostgreSQL write-ahead log.\n\n"), progname);
760 peter@eisentraut.org 1177 : 1 : printf(_("Usage:\n"));
1178 : 1 : printf(_(" %s [OPTION]... DATADIR\n"), progname);
1179 : :
1180 : 1 : printf(_("\nOptions:\n"));
1181 : 1 : printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
1182 : 1 : printf(_(" -f, --force force update to be done even after unclean shutdown or\n"
1183 : : " if pg_control values had to be guessed\n"));
1184 : 1 : printf(_(" -n, --dry-run no update, just show what would be done\n"));
1185 : 1 : printf(_(" -V, --version output version information, then exit\n"));
1186 : 1 : printf(_(" -?, --help show this help, then exit\n"));
1187 : :
1188 : 1 : printf(_("\nOptions to override control file values:\n"));
2774 peter_e@gmx.net 1189 : 1 : printf(_(" -c, --commit-timestamp-ids=XID,XID\n"
1190 : : " set oldest and newest transactions bearing\n"
1191 : : " commit timestamp (zero means no change)\n"));
1554 bruce@momjian.us 1192 : 1 : printf(_(" -e, --epoch=XIDEPOCH set next transaction ID epoch\n"));
1193 : 1 : printf(_(" -l, --next-wal-file=WALFILE set minimum starting location for new WAL\n"));
1194 : 1 : printf(_(" -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID\n"));
1195 : 1 : printf(_(" -o, --next-oid=OID set next OID\n"));
1196 : 1 : printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n"));
1197 : 1 : printf(_(" -u, --oldest-transaction-id=XID set oldest transaction ID\n"));
1198 : 1 : printf(_(" -x, --next-transaction-id=XID set next transaction ID\n"));
181 peter@eisentraut.org 1199 : 1 : printf(_(" --char-signedness=OPTION set char signedness to \"signed\" or \"unsigned\"\n"));
1554 bruce@momjian.us 1200 : 1 : printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n"));
1201 : :
2068 peter@eisentraut.org 1202 : 1 : printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1203 : 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
8472 bruce@momjian.us 1204 : 1 : }
|