LCOV - differential code coverage report
Current view: top level - src/bin/pg_rewind - pg_rewind.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 83.9 % 404 339 17 45 3 19 200 19 101 40 209 3 12
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 14 14 12 2 13 1
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 100.0 % 18 18 18
Legend: Lines: hit not hit (180,240] days: 100.0 % 1 1 1
(240..) days: 83.1 % 385 320 17 45 3 19 200 101 39 197
Function coverage date bins:
[..60] days: 100.0 % 2 2 2
(240..) days: 50.0 % 24 12 12 12

 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 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a