Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_rewind.c
4 : * Synchronizes a PostgreSQL data directory to a new timeline
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : *
8 : *-------------------------------------------------------------------------
9 : */
10 : #include "postgres_fe.h"
11 :
12 : #include <sys/stat.h>
13 : #include <fcntl.h>
14 : #include <time.h>
15 : #include <unistd.h>
16 :
17 : #include "access/timeline.h"
18 : #include "access/xlog_internal.h"
19 : #include "catalog/catversion.h"
20 : #include "catalog/pg_control.h"
21 : #include "common/controldata_utils.h"
22 : #include "common/file_perm.h"
23 : #include "common/restricted_token.h"
24 : #include "common/string.h"
25 : #include "fe_utils/recovery_gen.h"
26 : #include "fe_utils/string_utils.h"
27 : #include "file_ops.h"
28 : #include "filemap.h"
29 : #include "getopt_long.h"
30 : #include "pg_rewind.h"
31 : #include "rewind_source.h"
32 : #include "storage/bufpage.h"
33 :
34 : static void usage(const char *progname);
35 :
36 : static void perform_rewind(filemap_t *filemap, rewind_source *source,
37 : XLogRecPtr chkptrec,
38 : TimeLineID chkpttli,
39 : XLogRecPtr chkptredo);
40 :
41 : static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli,
42 : XLogRecPtr checkpointloc);
43 :
44 : static void digestControlFile(ControlFileData *ControlFile,
45 : const char *content, size_t size);
46 : static void getRestoreCommand(const char *argv0);
47 : static void sanityChecks(void);
48 : static TimeLineHistoryEntry *getTimelineHistory(TimeLineID tli, bool is_source,
49 : int *nentries);
50 : static void findCommonAncestorTimeline(TimeLineHistoryEntry *a_history,
51 : int a_nentries,
52 : TimeLineHistoryEntry *b_history,
53 : int b_nentries,
54 : XLogRecPtr *recptr, int *tliIndex);
55 : static void ensureCleanShutdown(const char *argv0);
56 : static void disconnect_atexit(void);
57 :
58 : static ControlFileData ControlFile_target;
59 : static ControlFileData ControlFile_source;
60 : static ControlFileData ControlFile_source_after;
61 :
62 : const char *progname;
63 : int WalSegSz;
64 :
65 : /* Configuration options */
66 : char *datadir_target = NULL;
67 : char *datadir_source = NULL;
68 : char *connstr_source = NULL;
69 : char *restore_command = NULL;
70 : char *config_file = NULL;
71 :
72 : static bool debug = false;
73 : bool showprogress = false;
74 : bool dry_run = false;
75 : bool do_sync = true;
76 : bool restore_wal = false;
77 :
78 : /* Target history */
79 : TimeLineHistoryEntry *targetHistory;
80 : int targetNentries;
81 :
82 : /* Progress counters */
83 : uint64 fetch_size;
84 : uint64 fetch_done;
85 :
86 : static PGconn *conn;
87 : static rewind_source *source;
88 :
89 : static void
2939 heikki.linnakangas 90 GIC 1 : usage(const char *progname)
91 : {
2848 peter_e 92 1 : printf(_("%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"), progname);
2939 heikki.linnakangas 93 1 : printf(_("Usage:\n %s [OPTION]...\n\n"), progname);
94 1 : printf(_("Options:\n"));
1073 peter 95 1 : printf(_(" -c, --restore-target-wal use restore_command in target configuration to\n"
1073 peter 96 ECB : " retrieve WAL files from archives\n"));
2848 peter_e 97 GIC 1 : printf(_(" -D, --target-pgdata=DIRECTORY existing data directory to modify\n"));
2762 peter_e 98 CBC 1 : printf(_(" --source-pgdata=DIRECTORY source data directory to synchronize with\n"));
99 1 : printf(_(" --source-server=CONNSTR source server to synchronize with\n"));
2848 100 1 : printf(_(" -n, --dry-run stop before modifying anything\n"));
1441 alvherre 101 1 : printf(_(" -N, --no-sync do not wait for changes to be written\n"
102 : " safely to disk\n"));
2848 peter_e 103 1 : printf(_(" -P, --progress write progress messages\n"));
1073 peter 104 1 : printf(_(" -R, --write-recovery-conf write configuration for replication\n"
1073 peter 105 ECB : " (requires --source-server)\n"));
363 peter 106 CBC 1 : printf(_(" --config-file=FILENAME use specified main server configuration\n"
363 peter 107 ECB : " file when running target cluster\n"));
2848 peter_e 108 GIC 1 : printf(_(" --debug write a lot of debug messages\n"));
1073 peter 109 CBC 1 : printf(_(" --no-ensure-shutdown do not automatically fix unclean shutdown\n"));
2848 peter_e 110 1 : printf(_(" -V, --version output version information, then exit\n"));
2848 peter_e 111 GIC 1 : printf(_(" -?, --help show this help, then exit\n"));
1136 peter 112 CBC 1 : printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1136 peter 113 GIC 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
2939 heikki.linnakangas 114 CBC 1 : }
2939 heikki.linnakangas 115 ECB :
116 :
117 : int
2939 heikki.linnakangas 118 CBC 24 : main(int argc, char **argv)
2939 heikki.linnakangas 119 ECB : {
120 : static struct option long_options[] = {
121 : {"help", no_argument, NULL, '?'},
122 : {"target-pgdata", required_argument, NULL, 'D'},
123 : {"write-recovery-conf", no_argument, NULL, 'R'},
124 : {"source-pgdata", required_argument, NULL, 1},
125 : {"source-server", required_argument, NULL, 2},
126 : {"no-ensure-shutdown", no_argument, NULL, 4},
127 : {"config-file", required_argument, NULL, 5},
128 : {"version", no_argument, NULL, 'V'},
129 : {"restore-target-wal", no_argument, NULL, 'c'},
130 : {"dry-run", no_argument, NULL, 'n'},
131 : {"no-sync", no_argument, NULL, 'N'},
132 : {"progress", no_argument, NULL, 'P'},
133 : {"debug", no_argument, NULL, 3},
134 : {NULL, 0, NULL, 0}
135 : };
136 : int option_index;
137 : int c;
138 : XLogRecPtr divergerec;
139 : int lastcommontliIndex;
140 : XLogRecPtr chkptrec;
141 : TimeLineID chkpttli;
142 : XLogRecPtr chkptredo;
143 : TimeLineID source_tli;
144 : TimeLineID target_tli;
145 : XLogRecPtr target_wal_endrec;
146 : size_t size;
147 : char *buffer;
1290 alvherre 148 GIC 24 : bool no_ensure_shutdown = false;
149 : bool rewind_needed;
1287 150 24 : bool writerecoveryconf = false;
151 : filemap_t *filemap;
152 :
1469 peter 153 24 : pg_logging_init(argv[0]);
2924 heikki.linnakangas 154 24 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_rewind"));
2939 155 24 : progname = get_progname(argv[0]);
2939 heikki.linnakangas 156 ECB :
157 : /* Process command-line arguments */
2939 heikki.linnakangas 158 CBC 24 : if (argc > 1)
159 : {
2939 heikki.linnakangas 160 GIC 24 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
2939 heikki.linnakangas 161 ECB : {
2939 heikki.linnakangas 162 CBC 1 : usage(progname);
163 1 : exit(0);
164 : }
2939 heikki.linnakangas 165 GIC 23 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
2939 heikki.linnakangas 166 ECB : {
2939 heikki.linnakangas 167 GIC 1 : puts("pg_rewind (PostgreSQL) " PG_VERSION);
2939 heikki.linnakangas 168 CBC 1 : exit(0);
169 : }
2939 heikki.linnakangas 170 ECB : }
171 :
1103 michael 172 GIC 121 : while ((c = getopt_long(argc, argv, "cD:nNPR", long_options, &option_index)) != -1)
2939 heikki.linnakangas 173 ECB : {
2939 heikki.linnakangas 174 GIC 100 : switch (c)
2939 heikki.linnakangas 175 ECB : {
1103 michael 176 CBC 1 : case 'c':
1103 michael 177 GIC 1 : restore_wal = true;
178 1 : break;
179 :
2939 heikki.linnakangas 180 LBC 0 : case 'P':
2939 heikki.linnakangas 181 UIC 0 : showprogress = true;
2939 heikki.linnakangas 182 LBC 0 : break;
183 :
2939 heikki.linnakangas 184 CBC 1 : case 'n':
185 1 : dry_run = true;
186 1 : break;
187 :
1734 michael 188 GBC 16 : case 'N':
189 16 : do_sync = false;
190 16 : break;
191 :
1287 alvherre 192 CBC 6 : case 'R':
193 6 : writerecoveryconf = true;
194 6 : break;
195 :
2939 heikki.linnakangas 196 20 : case 3:
197 20 : debug = true;
934 tgl 198 20 : pg_logging_increase_verbosity();
2939 heikki.linnakangas 199 GIC 20 : break;
2939 heikki.linnakangas 200 ECB :
2939 heikki.linnakangas 201 CBC 21 : case 'D': /* -D or --target-pgdata */
202 21 : datadir_target = pg_strdup(optarg);
2939 heikki.linnakangas 203 GIC 21 : break;
2939 heikki.linnakangas 204 ECB :
2939 heikki.linnakangas 205 CBC 14 : case 1: /* --source-pgdata */
206 14 : datadir_source = pg_strdup(optarg);
207 14 : break;
208 :
209 7 : case 2: /* --source-server */
210 7 : connstr_source = pg_strdup(optarg);
211 7 : break;
212 :
1290 alvherre 213 3 : case 4:
214 3 : no_ensure_shutdown = true;
215 3 : break;
216 :
367 michael 217 10 : case 5:
218 10 : config_file = pg_strdup(optarg);
219 10 : break;
220 :
366 tgl 221 1 : default:
366 tgl 222 ECB : /* getopt_long already emitted a complaint */
366 tgl 223 CBC 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
366 tgl 224 GIC 1 : exit(1);
2939 heikki.linnakangas 225 ECB : }
226 : }
227 :
2939 heikki.linnakangas 228 GIC 21 : if (datadir_source == NULL && connstr_source == NULL)
2939 heikki.linnakangas 229 ECB : {
1469 peter 230 GIC 1 : pg_log_error("no source specified (--source-pgdata or --source-server)");
366 tgl 231 CBC 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
2939 heikki.linnakangas 232 1 : exit(1);
233 : }
234 :
2375 heikki.linnakangas 235 GIC 20 : if (datadir_source != NULL && connstr_source != NULL)
2375 heikki.linnakangas 236 ECB : {
1469 peter 237 GIC 1 : pg_log_error("only one of --source-pgdata or --source-server can be specified");
366 tgl 238 CBC 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
2375 heikki.linnakangas 239 1 : exit(1);
2375 heikki.linnakangas 240 ECB : }
241 :
2939 heikki.linnakangas 242 GIC 19 : if (datadir_target == NULL)
2939 heikki.linnakangas 243 ECB : {
1469 peter 244 UIC 0 : pg_log_error("no target data directory specified (--target-pgdata)");
366 tgl 245 LBC 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
2939 heikki.linnakangas 246 0 : exit(1);
2939 heikki.linnakangas 247 ECB : }
248 :
1287 alvherre 249 GIC 19 : if (writerecoveryconf && connstr_source == NULL)
1287 alvherre 250 ECB : {
1075 peter 251 GIC 1 : pg_log_error("no source server information (--source-server) specified for --write-recovery-conf");
366 tgl 252 GBC 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
1287 alvherre 253 1 : exit(1);
1287 alvherre 254 EUB : }
255 :
2848 peter_e 256 GIC 18 : if (optind < argc)
2939 heikki.linnakangas 257 ECB : {
1469 peter 258 GIC 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
1469 peter 259 ECB : argv[optind]);
366 tgl 260 CBC 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
2939 heikki.linnakangas 261 1 : exit(1);
262 : }
263 :
2924 heikki.linnakangas 264 ECB : /*
265 : * Don't allow pg_rewind to be run as root, to avoid overwriting the
266 : * ownership of files in the data directory. We need only check for root
267 : * -- any other user won't have sufficient permissions to modify files in
268 : * the data directory.
269 : */
270 : #ifndef WIN32
2924 heikki.linnakangas 271 GIC 17 : if (geteuid() == 0)
272 : {
1469 peter 273 UIC 0 : pg_log_error("cannot be executed by \"root\"");
366 tgl 274 0 : pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
275 : progname);
1826 magnus 276 0 : exit(1);
277 : }
278 : #endif
2924 heikki.linnakangas 279 ECB :
1469 peter 280 GIC 17 : get_restricted_token();
2924 heikki.linnakangas 281 EUB :
1782 tgl 282 : /* Set mask based on PGDATA permissions */
1782 tgl 283 GIC 17 : if (!GetDataDirectoryCreatePerm(datadir_target))
366 tgl 284 UBC 0 : pg_fatal("could not read permissions of directory \"%s\": %m",
285 : datadir_target);
286 :
1782 tgl 287 GIC 17 : umask(pg_mode_mask);
1782 tgl 288 ECB :
1103 michael 289 GIC 17 : getRestoreCommand(argv[0]);
290 :
1287 alvherre 291 CBC 17 : atexit(disconnect_atexit);
1287 alvherre 292 EUB :
293 : /*
294 : * Ok, we have all the options and we're ready to start. First, connect to
886 heikki.linnakangas 295 ECB : * remote server.
296 : */
886 heikki.linnakangas 297 CBC 17 : if (connstr_source)
298 : {
299 6 : conn = PQconnectdb(connstr_source);
300 :
886 heikki.linnakangas 301 GIC 6 : if (PQstatus(conn) == CONNECTION_BAD)
883 peter 302 UIC 0 : pg_fatal("%s", PQerrorMessage(conn));
303 :
886 heikki.linnakangas 304 GIC 6 : if (showprogress)
886 heikki.linnakangas 305 LBC 0 : pg_log_info("connected to server");
306 :
886 heikki.linnakangas 307 CBC 6 : source = init_libpq_source(conn);
308 : }
886 heikki.linnakangas 309 ECB : else
886 heikki.linnakangas 310 GBC 11 : source = init_local_source(datadir_source);
311 :
1290 alvherre 312 ECB : /*
886 heikki.linnakangas 313 EUB : * Check the status of the target instance.
314 : *
1280 michael 315 ECB : * If the target instance was not cleanly shut down, start and stop the
316 : * target cluster once in single-user mode to enforce recovery to finish,
317 : * ensuring that the cluster can be used by pg_rewind. Note that if
318 : * no_ensure_shutdown is specified, pg_rewind ignores this step, and users
319 : * need to make sure by themselves that the target cluster is in a clean
320 : * state.
321 : */
886 heikki.linnakangas 322 GIC 17 : buffer = slurpFile(datadir_target, "global/pg_control", &size);
323 17 : digestControlFile(&ControlFile_target, buffer, size);
324 17 : pg_free(buffer);
325 :
1290 alvherre 326 17 : if (!no_ensure_shutdown &&
327 14 : ControlFile_target.state != DB_SHUTDOWNED &&
328 11 : ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY)
329 : {
1290 alvherre 330 CBC 10 : ensureCleanShutdown(argv[0]);
1290 alvherre 331 ECB :
1290 alvherre 332 CBC 9 : buffer = slurpFile(datadir_target, "global/pg_control", &size);
1290 alvherre 333 GIC 9 : digestControlFile(&ControlFile_target, buffer, size);
1290 alvherre 334 CBC 9 : pg_free(buffer);
1290 alvherre 335 ECB : }
336 :
886 heikki.linnakangas 337 GIC 16 : buffer = source->fetch_file(source, "global/pg_control", &size);
2939 heikki.linnakangas 338 CBC 16 : digestControlFile(&ControlFile_source, buffer, size);
2939 heikki.linnakangas 339 GIC 16 : pg_free(buffer);
2939 heikki.linnakangas 340 ECB :
2939 heikki.linnakangas 341 CBC 16 : sanityChecks();
2939 heikki.linnakangas 342 ECB :
343 : /*
344 : * Usually, the TLI can be found in the latest checkpoint record. But if
345 : * the source server is just being promoted (or it's a standby that's
346 : * following a primary that's just being promoted), and the checkpoint
347 : * requested by the promotion hasn't completed yet, the latest timeline is
348 : * in minRecoveryPoint. So we check which is later, the TLI of the
349 : * minRecoveryPoint or the latest checkpoint.
350 : */
45 heikki.linnakangas 351 GNC 14 : source_tli = Max(ControlFile_source.minRecoveryPointTLI,
352 : ControlFile_source.checkPointCopy.ThisTimeLineID);
353 :
354 : /* Similarly for the target. */
355 14 : target_tli = Max(ControlFile_target.minRecoveryPointTLI,
356 : ControlFile_target.checkPointCopy.ThisTimeLineID);
357 :
358 : /*
359 : * Find the common ancestor timeline between the clusters.
886 heikki.linnakangas 360 ECB : *
2939 361 : * If both clusters are already on the same timeline, there's nothing to
362 : * do.
363 : */
45 heikki.linnakangas 364 GNC 14 : if (target_tli == source_tli)
365 : {
1469 peter 366 GIC 1 : pg_log_info("source and target cluster are on the same timeline");
2684 peter_e 367 1 : rewind_needed = false;
857 heikki.linnakangas 368 1 : target_wal_endrec = 0;
369 : }
370 : else
371 : {
372 : XLogRecPtr chkptendrec;
373 : TimeLineHistoryEntry *sourceHistory;
374 : int sourceNentries;
375 :
376 : /*
377 : * Retrieve timelines for both source and target, and find the point
378 : * where they diverged.
379 : */
45 heikki.linnakangas 380 GNC 13 : sourceHistory = getTimelineHistory(source_tli, true, &sourceNentries);
381 13 : targetHistory = getTimelineHistory(target_tli, false, &targetNentries);
382 :
383 13 : findCommonAncestorTimeline(sourceHistory, sourceNentries,
384 : targetHistory, targetNentries,
385 : &divergerec, &lastcommontliIndex);
857 heikki.linnakangas 386 ECB :
1469 peter 387 GIC 13 : pg_log_info("servers diverged at WAL location %X/%X on timeline %u",
388 : LSN_FORMAT_ARGS(divergerec),
1418 tgl 389 ECB : targetHistory[lastcommontliIndex].tli);
390 :
391 : /*
392 : * Don't need the source history anymore. The target history is still
393 : * needed by the routines in parsexlog.c, when we read the target WAL.
394 : */
45 heikki.linnakangas 395 GNC 13 : pfree(sourceHistory);
396 :
397 :
398 : /*
399 : * Determine the end-of-WAL on the target.
400 : *
401 : * The WAL ends at the last shutdown checkpoint, or at
402 : * minRecoveryPoint if it was a standby. (If we supported rewinding a
403 : * server that was not shut down cleanly, we would need to replay
404 : * until we reach the first invalid record, like crash recovery does.)
857 heikki.linnakangas 405 ECB : */
406 :
407 : /* read the checkpoint record on the target to see where it ends. */
857 heikki.linnakangas 408 CBC 13 : chkptendrec = readOneRecord(datadir_target,
857 heikki.linnakangas 409 ECB : ControlFile_target.checkPoint,
410 : targetNentries - 1,
411 : restore_command);
412 :
857 heikki.linnakangas 413 GIC 13 : if (ControlFile_target.minRecoveryPoint > chkptendrec)
414 : {
415 1 : target_wal_endrec = ControlFile_target.minRecoveryPoint;
416 : }
417 : else
418 : {
419 12 : target_wal_endrec = chkptendrec;
420 : }
857 heikki.linnakangas 421 ECB :
2939 422 : /*
423 : * Check for the possibility that the target is in fact a direct
2495 rhaas 424 : * ancestor of the source. In that case, there is no divergent history
425 : * in the target that needs rewinding.
426 : */
857 heikki.linnakangas 427 GIC 13 : if (target_wal_endrec > divergerec)
2684 peter_e 428 ECB : {
2939 heikki.linnakangas 429 GIC 13 : rewind_needed = true;
430 : }
431 : else
432 : {
433 : /* the last common checkpoint record must be part of target WAL */
857 heikki.linnakangas 434 UIC 0 : Assert(target_wal_endrec == divergerec);
435 :
857 heikki.linnakangas 436 LBC 0 : rewind_needed = false;
437 : }
438 : }
439 :
2939 heikki.linnakangas 440 GIC 14 : if (!rewind_needed)
441 : {
1469 peter 442 1 : pg_log_info("no rewind required");
1283 michael 443 1 : if (writerecoveryconf && !dry_run)
1287 alvherre 444 UIC 0 : WriteRecoveryConfig(conn, datadir_target,
445 : GenerateRecoveryConfig(conn, NULL));
2939 heikki.linnakangas 446 GIC 1 : exit(0);
447 : }
448 :
1103 michael 449 CBC 13 : findLastCheckpoint(datadir_target, divergerec, lastcommontliIndex,
450 : &chkptrec, &chkpttli, &chkptredo, restore_command);
1469 peter 451 GIC 13 : pg_log_info("rewinding from last common checkpoint at %X/%X on timeline %u",
452 : LSN_FORMAT_ARGS(chkptrec), chkpttli);
453 :
886 heikki.linnakangas 454 ECB : /* Initialize the hash table to track the status of each file */
886 heikki.linnakangas 455 GIC 13 : filehash_init();
886 heikki.linnakangas 456 ECB :
457 : /*
458 : * Collect information about all files in the both data directories.
459 : */
1469 peter 460 CBC 13 : if (showprogress)
1469 peter 461 UIC 0 : pg_log_info("reading source file list");
886 heikki.linnakangas 462 GIC 13 : source->traverse_files(source, &process_source_file);
463 :
1469 peter 464 13 : if (showprogress)
1469 peter 465 UIC 0 : pg_log_info("reading target file list");
2916 heikki.linnakangas 466 GIC 13 : traverse_datadir(datadir_target, &process_target_file);
467 :
2939 heikki.linnakangas 468 ECB : /*
469 : * Read the target WAL from last checkpoint before the point of fork, to
470 : * extract all the pages that were modified on the target cluster after
471 : * the fork.
472 : */
1469 peter 473 GIC 13 : if (showprogress)
1469 peter 474 UIC 0 : pg_log_info("reading WAL in target");
2686 teodor 475 GBC 13 : extractPageMap(datadir_target, chkptrec, lastcommontliIndex,
476 : target_wal_endrec, restore_command);
2939 heikki.linnakangas 477 EUB :
478 : /*
479 : * We have collected all information we need from both systems. Decide
480 : * what to do with each file.
886 heikki.linnakangas 481 ECB : */
886 heikki.linnakangas 482 GIC 13 : filemap = decide_file_actions();
2939 heikki.linnakangas 483 CBC 13 : if (showprogress)
886 heikki.linnakangas 484 LBC 0 : calculate_totals(filemap);
2939 heikki.linnakangas 485 EUB :
486 : /* this is too verbose even for verbose mode */
2939 heikki.linnakangas 487 CBC 13 : if (debug)
886 heikki.linnakangas 488 GIC 13 : print_filemap(filemap);
489 :
2939 heikki.linnakangas 490 ECB : /*
491 : * Ok, we're ready to start copying things over.
492 : */
2939 heikki.linnakangas 493 GIC 13 : if (showprogress)
494 : {
1469 peter 495 UIC 0 : pg_log_info("need to copy %lu MB (total source directory size is %lu MB)",
1418 tgl 496 ECB : (unsigned long) (filemap->fetch_size / (1024 * 1024)),
497 : (unsigned long) (filemap->total_size / (1024 * 1024)));
498 :
2939 heikki.linnakangas 499 UIC 0 : fetch_size = filemap->fetch_size;
500 0 : fetch_done = 0;
2939 heikki.linnakangas 501 ECB : }
2939 heikki.linnakangas 502 EUB :
2939 heikki.linnakangas 503 ECB : /*
504 : * We have now collected all the information we need from both systems,
886 505 : * and we are ready to start modifying the target directory.
886 heikki.linnakangas 506 EUB : *
886 heikki.linnakangas 507 ECB : * This is the point of no return. Once we start copying things, there is
508 : * no turning back!
509 : */
886 heikki.linnakangas 510 GIC 13 : perform_rewind(filemap, source, chkptrec, chkpttli, chkptredo);
511 :
512 12 : if (showprogress)
886 heikki.linnakangas 513 UIC 0 : pg_log_info("syncing target data directory");
886 heikki.linnakangas 514 CBC 12 : sync_target_dir();
886 heikki.linnakangas 515 EUB :
886 heikki.linnakangas 516 ECB : /* Also update the standby configuration, if requested. */
886 heikki.linnakangas 517 GIC 12 : if (writerecoveryconf && !dry_run)
518 5 : WriteRecoveryConfig(conn, datadir_target,
519 : GenerateRecoveryConfig(conn, NULL));
520 :
521 : /* don't need the source connection anymore */
522 12 : source->destroy(source);
886 heikki.linnakangas 523 CBC 12 : if (conn)
886 heikki.linnakangas 524 ECB : {
886 heikki.linnakangas 525 GBC 6 : PQfinish(conn);
886 heikki.linnakangas 526 GIC 6 : conn = NULL;
527 : }
886 heikki.linnakangas 528 ECB :
886 heikki.linnakangas 529 CBC 12 : pg_log_info("Done!");
530 :
886 heikki.linnakangas 531 GIC 12 : return 0;
532 : }
533 :
886 heikki.linnakangas 534 ECB : /*
535 : * Perform the rewind.
886 heikki.linnakangas 536 EUB : *
537 : * We have already collected all the information we need from the
538 : * target and the source.
539 : */
540 : static void
886 heikki.linnakangas 541 GBC 13 : perform_rewind(filemap_t *filemap, rewind_source *source,
542 : XLogRecPtr chkptrec,
543 : TimeLineID chkpttli,
544 : XLogRecPtr chkptredo)
545 : {
546 : XLogRecPtr endrec;
547 : TimeLineID endtli;
548 : ControlFileData ControlFile_new;
549 : size_t size;
550 : char *buffer;
886 heikki.linnakangas 551 ECB :
552 : /*
553 : * Execute the actions in the file map, fetching data from the source
886 heikki.linnakangas 554 EUB : * system as needed.
886 heikki.linnakangas 555 ECB : */
886 heikki.linnakangas 556 GIC 14832 : for (int i = 0; i < filemap->nentries; i++)
557 : {
886 heikki.linnakangas 558 CBC 14820 : file_entry_t *entry = filemap->entries[i];
886 heikki.linnakangas 559 ECB :
560 : /*
561 : * If this is a relation file, copy the modified blocks.
562 : *
563 : * This is in addition to any other changes.
564 : */
886 heikki.linnakangas 565 GIC 14820 : if (entry->target_pages_to_overwrite.bitmapsize > 0)
886 heikki.linnakangas 566 ECB : {
567 : datapagemap_iterator_t *iter;
568 : BlockNumber blkno;
569 : off_t offset;
570 :
886 heikki.linnakangas 571 GIC 390 : iter = datapagemap_iterate(&entry->target_pages_to_overwrite);
886 heikki.linnakangas 572 CBC 2027 : while (datapagemap_next(iter, &blkno))
573 : {
886 heikki.linnakangas 574 GIC 1637 : offset = blkno * BLCKSZ;
575 1637 : source->queue_fetch_range(source, entry->path, offset, BLCKSZ);
576 : }
577 390 : pg_free(iter);
578 : }
579 :
580 14820 : switch (entry->action)
581 : {
886 heikki.linnakangas 582 CBC 9923 : case FILE_ACTION_NONE:
583 : /* nothing else to do */
886 heikki.linnakangas 584 GIC 9923 : break;
585 :
586 4180 : case FILE_ACTION_COPY:
369 dgustafsson 587 4180 : source->queue_fetch_file(source, entry->path, entry->source_size);
886 heikki.linnakangas 588 4179 : break;
589 :
590 4 : case FILE_ACTION_TRUNCATE:
591 4 : truncate_target_file(entry->path, entry->source_size);
592 4 : break;
593 :
594 5 : case FILE_ACTION_COPY_TAIL:
595 5 : source->queue_fetch_range(source, entry->path,
596 5 : entry->target_size,
886 heikki.linnakangas 597 CBC 5 : entry->source_size - entry->target_size);
886 heikki.linnakangas 598 GIC 5 : break;
886 heikki.linnakangas 599 ECB :
886 heikki.linnakangas 600 GIC 700 : case FILE_ACTION_REMOVE:
601 700 : remove_target(entry);
602 700 : break;
603 :
604 8 : case FILE_ACTION_CREATE:
605 8 : create_target(entry);
886 heikki.linnakangas 606 CBC 8 : break;
607 :
886 heikki.linnakangas 608 UIC 0 : case FILE_ACTION_UNDECIDED:
695 peter 609 0 : pg_fatal("no action decided for file \"%s\"", entry->path);
610 : break;
611 : }
886 heikki.linnakangas 612 ECB : }
613 :
614 : /* Complete any remaining range-fetches that we queued up above. */
886 heikki.linnakangas 615 CBC 12 : source->finish_fetch(source);
2939 heikki.linnakangas 616 ECB :
886 heikki.linnakangas 617 GIC 12 : close_target_file();
2939 heikki.linnakangas 618 ECB :
2939 heikki.linnakangas 619 GIC 12 : progress_report(true);
620 :
878 heikki.linnakangas 621 ECB : /*
622 : * Fetch the control file from the source last. This ensures that the
623 : * minRecoveryPoint is up-to-date.
624 : */
878 heikki.linnakangas 625 CBC 12 : buffer = source->fetch_file(source, "global/pg_control", &size);
878 heikki.linnakangas 626 GIC 12 : digestControlFile(&ControlFile_source_after, buffer, size);
878 heikki.linnakangas 627 CBC 12 : pg_free(buffer);
878 heikki.linnakangas 628 ECB :
629 : /*
630 : * Sanity check: If the source is a local system, the control file should
631 : * not have changed since we started.
632 : *
633 : * XXX: We assume it hasn't been modified, but actually, what could go
634 : * wrong? The logic handles a libpq source that's modified concurrently,
635 : * why not a local datadir?
636 : */
878 heikki.linnakangas 637 CBC 12 : if (datadir_source &&
638 6 : memcmp(&ControlFile_source, &ControlFile_source_after,
878 heikki.linnakangas 639 ECB : sizeof(ControlFileData)) != 0)
640 : {
878 heikki.linnakangas 641 LBC 0 : pg_fatal("source system was modified while pg_rewind was running");
878 heikki.linnakangas 642 ECB : }
643 :
1469 peter 644 GIC 12 : if (showprogress)
1469 peter 645 LBC 0 : pg_log_info("creating backup label and updating control file");
2939 heikki.linnakangas 646 ECB :
647 : /*
648 : * Create a backup label file, to tell the target where to begin the WAL
878 heikki.linnakangas 649 EUB : * replay. Normally, from the last common checkpoint between the source
650 : * and the target. But if the source is a standby server, it's possible
651 : * that the last common checkpoint is *after* the standby's restartpoint.
652 : * That implies that the source server has applied the checkpoint record,
653 : * but hasn't performed a corresponding restartpoint yet. Make sure we
654 : * start at the restartpoint's redo point in that case.
655 : *
878 heikki.linnakangas 656 ECB : * Use the old version of the source's control file for this. The server
657 : * might have finished the restartpoint after we started copying files,
658 : * but we must begin from the redo point at the time that started copying.
659 : */
878 heikki.linnakangas 660 CBC 12 : if (ControlFile_source.checkPointCopy.redo < chkptredo)
661 : {
878 heikki.linnakangas 662 GIC 2 : chkptredo = ControlFile_source.checkPointCopy.redo;
663 2 : chkpttli = ControlFile_source.checkPointCopy.ThisTimeLineID;
664 2 : chkptrec = ControlFile_source.checkPoint;
665 : }
878 heikki.linnakangas 666 CBC 12 : createBackupLabel(chkptredo, chkpttli, chkptrec);
2939 heikki.linnakangas 667 ECB :
878 668 : /*
669 : * Update control file of target, to tell the target how far it must
670 : * replay the WAL (minRecoveryPoint).
671 : */
2939 heikki.linnakangas 672 GIC 12 : if (connstr_source)
673 : {
674 : /*
675 : * The source is a live server. Like in an online backup, it's
676 : * important that we recover all the WAL that was generated while we
677 : * were copying files.
878 heikki.linnakangas 678 ECB : */
878 heikki.linnakangas 679 CBC 6 : if (ControlFile_source_after.state == DB_IN_ARCHIVE_RECOVERY)
680 : {
681 : /*
878 heikki.linnakangas 682 EUB : * Source is a standby server. We must replay to its
683 : * minRecoveryPoint.
684 : */
878 heikki.linnakangas 685 CBC 1 : endrec = ControlFile_source_after.minRecoveryPoint;
878 heikki.linnakangas 686 GBC 1 : endtli = ControlFile_source_after.minRecoveryPointTLI;
687 : }
688 : else
689 : {
690 : /*
691 : * Source is a production, non-standby, server. We must replay to
692 : * the last WAL insert location.
693 : */
878 heikki.linnakangas 694 GIC 5 : if (ControlFile_source_after.state != DB_IN_PRODUCTION)
878 heikki.linnakangas 695 UIC 0 : pg_fatal("source system was in unexpected state at end of rewind");
696 :
878 heikki.linnakangas 697 GIC 5 : endrec = source->get_current_wal_insert_lsn(source);
45 heikki.linnakangas 698 GNC 5 : endtli = Max(ControlFile_source_after.checkPointCopy.ThisTimeLineID,
699 : ControlFile_source_after.minRecoveryPointTLI);
700 : }
701 : }
2939 heikki.linnakangas 702 ECB : else
703 : {
878 704 : /*
705 : * Source is a local data directory. It should've shut down cleanly,
706 : * and we must replay to the latest shutdown checkpoint.
707 : */
878 heikki.linnakangas 708 CBC 6 : endrec = ControlFile_source_after.checkPoint;
878 heikki.linnakangas 709 GIC 6 : endtli = ControlFile_source_after.checkPointCopy.ThisTimeLineID;
710 : }
711 :
712 12 : memcpy(&ControlFile_new, &ControlFile_source_after, sizeof(ControlFileData));
2939 713 12 : ControlFile_new.minRecoveryPoint = endrec;
2939 heikki.linnakangas 714 CBC 12 : ControlFile_new.minRecoveryPointTLI = endtli;
2939 heikki.linnakangas 715 GIC 12 : ControlFile_new.state = DB_IN_ARCHIVE_RECOVERY;
1283 michael 716 12 : if (!dry_run)
717 11 : update_controlfile(datadir_target, &ControlFile_new, do_sync);
2939 heikki.linnakangas 718 12 : }
719 :
720 : static void
2939 heikki.linnakangas 721 CBC 16 : sanityChecks(void)
722 : {
723 : /* TODO Check that there's no backup_label in either cluster */
724 :
725 : /* Check system_identifier match */
2939 heikki.linnakangas 726 GIC 16 : if (ControlFile_target.system_identifier != ControlFile_source.system_identifier)
1469 peter 727 LBC 0 : pg_fatal("source and target clusters are from different systems");
2939 heikki.linnakangas 728 ECB :
729 : /* check version */
2939 heikki.linnakangas 730 GIC 16 : if (ControlFile_target.pg_control_version != PG_CONTROL_VERSION ||
731 16 : ControlFile_source.pg_control_version != PG_CONTROL_VERSION ||
732 16 : ControlFile_target.catalog_version_no != CATALOG_VERSION_NO ||
733 16 : ControlFile_source.catalog_version_no != CATALOG_VERSION_NO)
734 : {
1469 peter 735 UIC 0 : pg_fatal("clusters are not compatible with this version of pg_rewind");
2939 heikki.linnakangas 736 ECB : }
2939 heikki.linnakangas 737 EUB :
738 : /*
2939 heikki.linnakangas 739 ECB : * Target cluster need to use checksums or hint bit wal-logging, this to
740 : * prevent from data corruption that could occur because of hint bits.
741 : */
2939 heikki.linnakangas 742 GIC 16 : if (ControlFile_target.data_checksum_version != PG_DATA_CHECKSUM_VERSION &&
743 16 : !ControlFile_target.wal_log_hints)
744 : {
1469 peter 745 UIC 0 : pg_fatal("target server needs to use either data checksums or \"wal_log_hints = on\"");
746 : }
747 :
748 : /*
749 : * Target cluster better not be running. This doesn't guard against
2939 heikki.linnakangas 750 ECB : * someone starting the cluster concurrently. Also, this is probably more
2686 teodor 751 : * strict than necessary; it's OK if the target node was not shut down
752 : * cleanly, as long as it isn't running at the moment.
753 : */
2686 teodor 754 CBC 16 : if (ControlFile_target.state != DB_SHUTDOWNED &&
755 2 : ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY)
1469 peter 756 1 : pg_fatal("target server must be shut down cleanly");
2939 heikki.linnakangas 757 ECB :
758 : /*
759 : * When the source is a data directory, also require that the source
760 : * server is shut down. There isn't any very strong reason for this
761 : * limitation, but better safe than sorry.
762 : */
2686 teodor 763 CBC 15 : if (datadir_source &&
2686 teodor 764 GIC 9 : ControlFile_source.state != DB_SHUTDOWNED &&
765 2 : ControlFile_source.state != DB_SHUTDOWNED_IN_RECOVERY)
1469 peter 766 1 : pg_fatal("source data directory must be shut down cleanly");
2939 heikki.linnakangas 767 14 : }
2939 heikki.linnakangas 768 ECB :
1426 tgl 769 EUB : /*
770 : * Print a progress report based on the fetch_size and fetch_done variables.
771 : *
965 heikki.linnakangas 772 ECB : * Progress report is written at maximum once per second, except that the
773 : * last progress report is always printed.
774 : *
775 : * If finished is set to true, this is the last progress report. The cursor
776 : * is moved to the next line.
1426 tgl 777 EUB : */
778 : void
965 heikki.linnakangas 779 GIC 49126 : progress_report(bool finished)
780 : {
781 : static pg_time_t last_progress_report = 0;
782 : int percent;
783 : char fetch_done_str[32];
1426 tgl 784 ECB : char fetch_size_str[32];
785 : pg_time_t now;
786 :
1426 tgl 787 GBC 49126 : if (!showprogress)
1426 tgl 788 GIC 49126 : return;
789 :
1426 tgl 790 UIC 0 : now = time(NULL);
965 heikki.linnakangas 791 0 : if (now == last_progress_report && !finished)
1426 tgl 792 0 : return; /* Max once per second */
793 :
794 0 : last_progress_report = now;
795 0 : percent = fetch_size ? (int) ((fetch_done) * 100 / fetch_size) : 0;
1426 tgl 796 ECB :
797 : /*
798 : * Avoid overflowing past 100% or the full size. This may make the total
799 : * size number change as we approach the end of the backup (the estimate
800 : * will always be wrong if WAL is included), but that's better than having
801 : * the done column be bigger than the total.
802 : */
1426 tgl 803 UIC 0 : if (percent > 100)
804 0 : percent = 100;
1426 tgl 805 LBC 0 : if (fetch_done > fetch_size)
806 0 : fetch_size = fetch_done;
1426 tgl 807 ECB :
571 peter 808 LBC 0 : snprintf(fetch_done_str, sizeof(fetch_done_str), UINT64_FORMAT,
1426 tgl 809 ECB : fetch_done / 1024);
571 peter 810 UIC 0 : snprintf(fetch_size_str, sizeof(fetch_size_str), UINT64_FORMAT,
811 : fetch_size / 1024);
812 :
1426 tgl 813 0 : fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
1418 814 0 : (int) strlen(fetch_size_str), fetch_done_str, fetch_size_str,
815 : percent);
816 :
817 : /*
818 : * Stay on the same line if reporting to a terminal and we're not done
819 : * yet.
820 : */
964 heikki.linnakangas 821 LBC 0 : fputc((!finished && isatty(fileno(stderr))) ? '\r' : '\n', stderr);
822 : }
823 :
824 : /*
825 : * Find minimum from two WAL locations assuming InvalidXLogRecPtr means
826 : * infinity as src/include/access/timeline.h states. This routine should
827 : * be used only when comparing WAL locations related to history files.
828 : */
2686 teodor 829 ECB : static XLogRecPtr
2686 teodor 830 CBC 13 : MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
831 : {
2686 teodor 832 GBC 13 : if (XLogRecPtrIsInvalid(a))
833 1 : return b;
834 12 : else if (XLogRecPtrIsInvalid(b))
2686 teodor 835 GIC 12 : return a;
2686 teodor 836 EUB : else
2686 teodor 837 UBC 0 : return Min(a, b);
838 : }
839 :
840 : /*
841 : * Retrieve timeline history for the source or target system.
842 : */
843 : static TimeLineHistoryEntry *
45 heikki.linnakangas 844 GNC 26 : getTimelineHistory(TimeLineID tli, bool is_source, int *nentries)
2686 teodor 845 EUB : {
2495 rhaas 846 : TimeLineHistoryEntry *history;
847 :
2686 teodor 848 : /*
849 : * Timeline 1 does not have a history file, so there is no need to check
850 : * and fake an entry with infinite start and end positions.
851 : */
2686 teodor 852 GBC 26 : if (tli == 1)
853 : {
2686 teodor 854 GIC 12 : history = (TimeLineHistoryEntry *) pg_malloc(sizeof(TimeLineHistoryEntry));
855 12 : history->tli = tli;
856 12 : history->begin = history->end = InvalidXLogRecPtr;
857 12 : *nentries = 1;
858 : }
2939 heikki.linnakangas 859 EUB : else
860 : {
861 : char path[MAXPGPATH];
862 : char *histfile;
863 :
2686 teodor 864 GIC 14 : TLHistoryFilePath(path, tli);
865 :
866 : /* Get history file from appropriate source */
45 heikki.linnakangas 867 GNC 14 : if (is_source)
886 heikki.linnakangas 868 CBC 12 : histfile = source->fetch_file(source, path, NULL);
2686 teodor 869 ECB : else
45 heikki.linnakangas 870 GNC 2 : histfile = slurpFile(datadir_target, path, NULL);
2939 heikki.linnakangas 871 ECB :
2686 teodor 872 GIC 14 : history = rewind_parseTimeLineHistory(histfile, tli, nentries);
2939 heikki.linnakangas 873 GBC 14 : pg_free(histfile);
874 : }
875 :
2686 teodor 876 GIC 26 : if (debug)
877 : {
878 : int i;
879 :
45 heikki.linnakangas 880 GNC 26 : if (is_source)
1469 peter 881 GIC 13 : pg_log_debug("Source timeline history:");
882 : else
45 heikki.linnakangas 883 GNC 13 : pg_log_debug("Target timeline history:");
884 :
885 : /*
2686 teodor 886 ECB : * Print the target timeline history.
887 : */
2686 teodor 888 CBC 41 : for (i = 0; i < targetNentries; i++)
2939 heikki.linnakangas 889 ECB : {
2686 teodor 890 : TimeLineHistoryEntry *entry;
2939 heikki.linnakangas 891 :
2686 teodor 892 GIC 15 : entry = &history[i];
718 peter 893 15 : pg_log_debug("%u: %X/%X - %X/%X", entry->tli,
894 : LSN_FORMAT_ARGS(entry->begin),
895 : LSN_FORMAT_ARGS(entry->end));
896 : }
897 : }
2939 heikki.linnakangas 898 ECB :
2686 teodor 899 GIC 26 : return history;
900 : }
2686 teodor 901 ECB :
902 : /*
903 : * Determine the TLI of the last common timeline in the timeline history of
904 : * two clusters. *tliIndex is set to the index of last common timeline in
905 : * the arrays, and *recptr is set to the position where the timeline history
906 : * diverged (ie. the first WAL record that's not the same in both clusters).
907 : */
908 : static void
45 heikki.linnakangas 909 GNC 13 : findCommonAncestorTimeline(TimeLineHistoryEntry *a_history, int a_nentries,
910 : TimeLineHistoryEntry *b_history, int b_nentries,
911 : XLogRecPtr *recptr, int *tliIndex)
2686 teodor 912 ECB : {
913 : int i,
914 : n;
915 :
916 : /*
917 : * Trace the history forward, until we hit the timeline diverge. It may
918 : * still be possible that the source and target nodes used the same
919 : * timeline number in their history but with different start position
920 : * depending on the history files that each node has fetched in previous
921 : * recovery processes. Hence check the start position of the new timeline
922 : * as well and move down by one extra timeline entry if they do not match.
923 : */
45 heikki.linnakangas 924 GNC 13 : n = Min(a_nentries, b_nentries);
2686 teodor 925 GIC 27 : for (i = 0; i < n; i++)
926 : {
45 heikki.linnakangas 927 GNC 14 : if (a_history[i].tli != b_history[i].tli ||
928 14 : a_history[i].begin != b_history[i].begin)
929 : break;
930 : }
931 :
2686 teodor 932 GIC 13 : if (i > 0)
933 : {
2686 teodor 934 CBC 13 : i--;
45 heikki.linnakangas 935 GNC 13 : *recptr = MinXLogRecPtr(a_history[i].end, b_history[i].end);
2686 teodor 936 GIC 13 : *tliIndex = i;
937 13 : return;
938 : }
939 : else
940 : {
1469 peter 941 UIC 0 : pg_fatal("could not find common ancestor of the source and target cluster's timelines");
942 : }
943 : }
944 :
945 :
946 : /*
2939 heikki.linnakangas 947 ECB : * Create a backup_label file that forces recovery to begin at the last common
948 : * checkpoint.
949 : */
950 : static void
2939 heikki.linnakangas 951 CBC 12 : createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpointloc)
952 : {
953 : XLogSegNo startsegno;
954 : time_t stamp_time;
2939 heikki.linnakangas 955 ECB : char strfbuf[128];
956 : char xlogfilename[MAXFNAMELEN];
957 : struct tm *tmp;
958 : char buf[1000];
959 : int len;
960 :
2028 andres 961 GIC 12 : XLByteToSeg(startpoint, startsegno, WalSegSz);
962 12 : XLogFileName(xlogfilename, starttli, startsegno, WalSegSz);
963 :
2939 heikki.linnakangas 964 EUB : /*
965 : * Construct backup label file
966 : */
2939 heikki.linnakangas 967 GIC 12 : stamp_time = time(NULL);
968 12 : tmp = localtime(&stamp_time);
969 12 : strftime(strfbuf, sizeof(strfbuf), "%Y-%m-%d %H:%M:%S %Z", tmp);
970 :
971 12 : len = snprintf(buf, sizeof(buf),
972 : "START WAL LOCATION: %X/%X (file %s)\n"
973 : "CHECKPOINT LOCATION: %X/%X\n"
2939 heikki.linnakangas 974 ECB : "BACKUP METHOD: pg_rewind\n"
975 : "BACKUP FROM: standby\n"
976 : "START TIME: %s\n",
977 : /* omit LABEL: line */
775 peter 978 GIC 12 : LSN_FORMAT_ARGS(startpoint), xlogfilename,
979 12 : LSN_FORMAT_ARGS(checkpointloc),
980 : strfbuf);
2939 heikki.linnakangas 981 12 : if (len >= sizeof(buf))
1469 peter 982 UIC 0 : pg_fatal("backup label buffer too small"); /* shouldn't happen */
983 :
2939 heikki.linnakangas 984 ECB : /* TODO: move old file out of the way, if any. */
2118 tgl 985 CBC 12 : open_target_file("backup_label", true); /* BACKUP_LABEL_FILE */
2939 heikki.linnakangas 986 GIC 12 : write_target_range(buf, 0, len);
2569 andres 987 12 : close_target_file();
2939 heikki.linnakangas 988 12 : }
989 :
2939 heikki.linnakangas 990 ECB : /*
991 : * Check CRC of control file
992 : */
993 : static void
2939 heikki.linnakangas 994 CBC 54 : checkControlFile(ControlFileData *ControlFile)
995 : {
996 : pg_crc32c crc;
997 :
998 : /* Calculate CRC */
2939 heikki.linnakangas 999 GIC 54 : INIT_CRC32C(crc);
1000 54 : COMP_CRC32C(crc, (char *) ControlFile, offsetof(ControlFileData, crc));
2939 heikki.linnakangas 1001 CBC 54 : FIN_CRC32C(crc);
2939 heikki.linnakangas 1002 ECB :
1003 : /* And simply compare it */
2939 heikki.linnakangas 1004 CBC 54 : if (!EQ_CRC32C(crc, ControlFile->crc))
1469 peter 1005 UBC 0 : pg_fatal("unexpected control file CRC");
2939 heikki.linnakangas 1006 GIC 54 : }
1007 :
2939 heikki.linnakangas 1008 ECB : /*
886 1009 : * Verify control file contents in the buffer 'content', and copy it to
1010 : * *ControlFile.
2939 1011 : */
1012 : static void
886 heikki.linnakangas 1013 GIC 54 : digestControlFile(ControlFileData *ControlFile, const char *content,
1014 : size_t size)
1015 : {
2090 tgl 1016 54 : if (size != PG_CONTROL_FILE_SIZE)
1469 peter 1017 LBC 0 : pg_fatal("unexpected control file size %d, expected %d",
1018 : (int) size, PG_CONTROL_FILE_SIZE);
1019 :
886 heikki.linnakangas 1020 GIC 54 : memcpy(ControlFile, content, sizeof(ControlFileData));
1021 :
2028 andres 1022 ECB : /* set and validate WalSegSz */
2028 andres 1023 CBC 54 : WalSegSz = ControlFile->xlog_seg_size;
2028 andres 1024 ECB :
2028 andres 1025 GIC 54 : if (!IsValidWalSegSize(WalSegSz))
1469 peter 1026 UIC 0 : pg_fatal(ngettext("WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte",
1469 peter 1027 ECB : "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes",
1788 peter_e 1028 EUB : WalSegSz),
2028 andres 1029 ECB : WalSegSz);
1030 :
1031 : /* Additional checks on control file */
2939 heikki.linnakangas 1032 GIC 54 : checkControlFile(ControlFile);
1033 54 : }
1034 :
1035 : /*
1103 michael 1036 ECB : * Get value of GUC parameter restore_command from the target cluster.
1037 : *
1038 : * This uses a logic based on "postgres -C" to get the value from the
1039 : * cluster.
1103 michael 1040 EUB : */
1041 : static void
1103 michael 1042 GIC 17 : getRestoreCommand(const char *argv0)
1103 michael 1043 ECB : {
1044 : int rc;
1045 : char postgres_exec_path[MAXPGPATH],
1046 : cmd_output[MAXPGPATH];
1047 : PQExpBuffer postgres_cmd;
1048 :
1103 michael 1049 GBC 17 : if (!restore_wal)
1103 michael 1050 GIC 16 : return;
1051 :
1052 : /* find postgres executable */
1053 1 : rc = find_other_exec(argv0, "postgres",
1054 : PG_BACKEND_VERSIONSTR,
1103 michael 1055 ECB : postgres_exec_path);
1056 :
1103 michael 1057 GIC 1 : if (rc < 0)
1058 : {
1059 : char full_path[MAXPGPATH];
1060 :
1103 michael 1061 UIC 0 : if (find_my_exec(argv0, full_path) < 0)
1062 0 : strlcpy(full_path, progname, sizeof(full_path));
1063 :
1064 0 : if (rc == -1)
366 tgl 1065 LBC 0 : pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"",
1066 : "postgres", progname, full_path);
1067 : else
366 tgl 1068 UIC 0 : pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s",
1069 : "postgres", full_path, progname);
1070 : }
1071 :
1103 michael 1072 ECB : /*
1073 : * Build a command able to retrieve the value of GUC parameter
1074 : * restore_command, if set.
1075 : */
404 michael 1076 CBC 1 : postgres_cmd = createPQExpBuffer();
1077 :
1078 : /* path to postgres, properly quoted */
404 michael 1079 GIC 1 : appendShellString(postgres_cmd, postgres_exec_path);
404 michael 1080 ECB :
1081 : /* add -D switch, with properly quoted data directory */
404 michael 1082 GIC 1 : appendPQExpBufferStr(postgres_cmd, " -D ");
1083 1 : appendShellString(postgres_cmd, datadir_target);
404 michael 1084 EUB :
367 1085 : /* add custom configuration file only if requested */
367 michael 1086 GIC 1 : if (config_file != NULL)
367 michael 1087 EUB : {
367 michael 1088 GBC 1 : appendPQExpBufferStr(postgres_cmd, " -c config_file=");
367 michael 1089 GIC 1 : appendShellString(postgres_cmd, config_file);
1090 : }
367 michael 1091 EUB :
1092 : /* add -C switch, for restore_command */
404 michael 1093 GIC 1 : appendPQExpBufferStr(postgres_cmd, " -C restore_command");
1094 :
1095 1 : if (!pipe_read_line(postgres_cmd->data, cmd_output, sizeof(cmd_output)))
1103 michael 1096 UIC 0 : exit(1);
1097 :
1103 michael 1098 GIC 1 : (void) pg_strip_crlf(cmd_output);
1103 michael 1099 ECB :
1103 michael 1100 GIC 1 : if (strcmp(cmd_output, "") == 0)
1066 peter 1101 UIC 0 : pg_fatal("restore_command is not set in the target cluster");
1103 michael 1102 ECB :
1103 michael 1103 GIC 1 : restore_command = pg_strdup(cmd_output);
1104 :
1103 michael 1105 CBC 1 : pg_log_debug("using for rewind restore_command = \'%s\'",
1103 michael 1106 ECB : restore_command);
1107 :
404 michael 1108 GIC 1 : destroyPQExpBuffer(postgres_cmd);
1103 michael 1109 ECB : }
1110 :
1111 :
1290 alvherre 1112 : /*
1113 : * Ensure clean shutdown of target instance by launching single-user mode
1114 : * postgres to do crash recovery.
1115 : */
1116 : static void
1290 alvherre 1117 GIC 10 : ensureCleanShutdown(const char *argv0)
1290 alvherre 1118 ECB : {
1290 alvherre 1119 EUB : int ret;
1120 : #define MAXCMDLEN (2 * MAXPGPATH)
1290 alvherre 1121 ECB : char exec_path[MAXPGPATH];
1122 : PQExpBuffer postgres_cmd;
1123 :
1290 alvherre 1124 EUB : /* locate postgres binary */
1290 alvherre 1125 GIC 10 : if ((ret = find_other_exec(argv0, "postgres",
1290 alvherre 1126 ECB : PG_BACKEND_VERSIONSTR,
1127 : exec_path)) < 0)
1128 : {
1129 : char full_path[MAXPGPATH];
1130 :
1290 alvherre 1131 LBC 0 : if (find_my_exec(argv0, full_path) < 0)
1290 alvherre 1132 UIC 0 : strlcpy(full_path, progname, sizeof(full_path));
1133 :
1134 0 : if (ret == -1)
366 tgl 1135 0 : pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"",
1136 : "postgres", progname, full_path);
1137 : else
1138 0 : pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s",
1139 : "postgres", full_path, progname);
1290 alvherre 1140 ECB : }
1141 :
1290 alvherre 1142 GIC 10 : pg_log_info("executing \"%s\" for target server to complete crash recovery",
1143 : exec_path);
1144 :
1145 : /*
1146 : * Skip processing if requested, but only after ensuring presence of
1147 : * postgres.
1290 alvherre 1148 ECB : */
1290 alvherre 1149 GIC 10 : if (dry_run)
1290 alvherre 1150 UIC 0 : return;
1151 :
1152 : /*
1153 : * Finally run postgres in single-user mode. There is no need to use
1280 michael 1154 EUB : * fsync here. This makes the recovery faster, and the target data folder
1155 : * is synced at the end anyway.
1156 : */
404 michael 1157 GBC 10 : postgres_cmd = createPQExpBuffer();
1290 alvherre 1158 EUB :
1159 : /* path to postgres, properly quoted */
404 michael 1160 GIC 10 : appendShellString(postgres_cmd, exec_path);
404 michael 1161 EUB :
1162 : /* add set of options with properly quoted data directory */
404 michael 1163 GIC 10 : appendPQExpBufferStr(postgres_cmd, " --single -F -D ");
1164 10 : appendShellString(postgres_cmd, datadir_target);
404 michael 1165 ECB :
1166 : /* add custom configuration file only if requested */
367 michael 1167 GIC 10 : if (config_file != NULL)
1168 : {
1169 9 : appendPQExpBufferStr(postgres_cmd, " -c config_file=");
1170 9 : appendShellString(postgres_cmd, config_file);
1171 : }
367 michael 1172 ECB :
404 michael 1173 EUB : /* finish with the database name, and a properly quoted redirection */
404 michael 1174 GIC 10 : appendPQExpBufferStr(postgres_cmd, " template1 < ");
1175 10 : appendShellString(postgres_cmd, DEVNULL);
1176 :
223 tgl 1177 GNC 10 : fflush(NULL);
404 michael 1178 GIC 10 : if (system(postgres_cmd->data) != 0)
1179 : {
1066 peter 1180 1 : pg_log_error("postgres single-user mode in target cluster failed");
366 tgl 1181 CBC 1 : pg_log_error_detail("Command was: %s", postgres_cmd->data);
366 tgl 1182 GIC 1 : exit(1);
1183 : }
404 michael 1184 ECB :
404 michael 1185 GIC 9 : destroyPQExpBuffer(postgres_cmd);
1186 : }
1287 alvherre 1187 ECB :
1188 : static void
1287 alvherre 1189 GIC 17 : disconnect_atexit(void)
1190 : {
1287 alvherre 1191 CBC 17 : if (conn != NULL)
1287 alvherre 1192 UIC 0 : PQfinish(conn);
1287 alvherre 1193 CBC 17 : }
|