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 15:15:32 Functions: 100.0 % 14 14 12 2 13 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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
      90 GIC           1 : usage(const char *progname)
      91                 : {
      92               1 :     printf(_("%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"), progname);
      93               1 :     printf(_("Usage:\n  %s [OPTION]...\n\n"), progname);
      94               1 :     printf(_("Options:\n"));
      95               1 :     printf(_("  -c, --restore-target-wal       use restore_command in target configuration to\n"
      96 ECB             :              "                                 retrieve WAL files from archives\n"));
      97 GIC           1 :     printf(_("  -D, --target-pgdata=DIRECTORY  existing data directory to modify\n"));
      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"));
     100               1 :     printf(_("  -n, --dry-run                  stop before modifying anything\n"));
     101               1 :     printf(_("  -N, --no-sync                  do not wait for changes to be written\n"
     102                 :              "                                 safely to disk\n"));
     103               1 :     printf(_("  -P, --progress                 write progress messages\n"));
     104               1 :     printf(_("  -R, --write-recovery-conf      write configuration for replication\n"
     105 ECB             :              "                                 (requires --source-server)\n"));
     106 CBC           1 :     printf(_("      --config-file=FILENAME     use specified main server configuration\n"
     107 ECB             :              "                                 file when running target cluster\n"));
     108 GIC           1 :     printf(_("      --debug                    write a lot of debug messages\n"));
     109 CBC           1 :     printf(_("      --no-ensure-shutdown       do not automatically fix unclean shutdown\n"));
     110               1 :     printf(_("  -V, --version                  output version information, then exit\n"));
     111 GIC           1 :     printf(_("  -?, --help                     show this help, then exit\n"));
     112 CBC           1 :     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     113 GIC           1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
     114 CBC           1 : }
     115 ECB             : 
     116                 : 
     117                 : int
     118 CBC          24 : main(int argc, char **argv)
     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;
     148 GIC          24 :     bool        no_ensure_shutdown = false;
     149                 :     bool        rewind_needed;
     150              24 :     bool        writerecoveryconf = false;
     151                 :     filemap_t  *filemap;
     152                 : 
     153              24 :     pg_logging_init(argv[0]);
     154              24 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_rewind"));
     155              24 :     progname = get_progname(argv[0]);
     156 ECB             : 
     157                 :     /* Process command-line arguments */
     158 CBC          24 :     if (argc > 1)
     159                 :     {
     160 GIC          24 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     161 ECB             :         {
     162 CBC           1 :             usage(progname);
     163               1 :             exit(0);
     164                 :         }
     165 GIC          23 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     166 ECB             :         {
     167 GIC           1 :             puts("pg_rewind (PostgreSQL) " PG_VERSION);
     168 CBC           1 :             exit(0);
     169                 :         }
     170 ECB             :     }
     171                 : 
     172 GIC         121 :     while ((c = getopt_long(argc, argv, "cD:nNPR", long_options, &option_index)) != -1)
     173 ECB             :     {
     174 GIC         100 :         switch (c)
     175 ECB             :         {
     176 CBC           1 :             case 'c':
     177 GIC           1 :                 restore_wal = true;
     178               1 :                 break;
     179                 : 
     180 LBC           0 :             case 'P':
     181 UIC           0 :                 showprogress = true;
     182 LBC           0 :                 break;
     183                 : 
     184 CBC           1 :             case 'n':
     185               1 :                 dry_run = true;
     186               1 :                 break;
     187                 : 
     188 GBC          16 :             case 'N':
     189              16 :                 do_sync = false;
     190              16 :                 break;
     191                 : 
     192 CBC           6 :             case 'R':
     193               6 :                 writerecoveryconf = true;
     194               6 :                 break;
     195                 : 
     196              20 :             case 3:
     197              20 :                 debug = true;
     198              20 :                 pg_logging_increase_verbosity();
     199 GIC          20 :                 break;
     200 ECB             : 
     201 CBC          21 :             case 'D':           /* -D or --target-pgdata */
     202              21 :                 datadir_target = pg_strdup(optarg);
     203 GIC          21 :                 break;
     204 ECB             : 
     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                 : 
     213               3 :             case 4:
     214               3 :                 no_ensure_shutdown = true;
     215               3 :                 break;
     216                 : 
     217              10 :             case 5:
     218              10 :                 config_file = pg_strdup(optarg);
     219              10 :                 break;
     220                 : 
     221               1 :             default:
     222 ECB             :                 /* getopt_long already emitted a complaint */
     223 CBC           1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     224 GIC           1 :                 exit(1);
     225 ECB             :         }
     226                 :     }
     227                 : 
     228 GIC          21 :     if (datadir_source == NULL && connstr_source == NULL)
     229 ECB             :     {
     230 GIC           1 :         pg_log_error("no source specified (--source-pgdata or --source-server)");
     231 CBC           1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     232               1 :         exit(1);
     233                 :     }
     234                 : 
     235 GIC          20 :     if (datadir_source != NULL && connstr_source != NULL)
     236 ECB             :     {
     237 GIC           1 :         pg_log_error("only one of --source-pgdata or --source-server can be specified");
     238 CBC           1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     239               1 :         exit(1);
     240 ECB             :     }
     241                 : 
     242 GIC          19 :     if (datadir_target == NULL)
     243 ECB             :     {
     244 UIC           0 :         pg_log_error("no target data directory specified (--target-pgdata)");
     245 LBC           0 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     246               0 :         exit(1);
     247 ECB             :     }
     248                 : 
     249 GIC          19 :     if (writerecoveryconf && connstr_source == NULL)
     250 ECB             :     {
     251 GIC           1 :         pg_log_error("no source server information (--source-server) specified for --write-recovery-conf");
     252 GBC           1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     253               1 :         exit(1);
     254 EUB             :     }
     255                 : 
     256 GIC          18 :     if (optind < argc)
     257 ECB             :     {
     258 GIC           1 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     259 ECB             :                      argv[optind]);
     260 CBC           1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     261               1 :         exit(1);
     262                 :     }
     263                 : 
     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
     271 GIC          17 :     if (geteuid() == 0)
     272                 :     {
     273 UIC           0 :         pg_log_error("cannot be executed by \"root\"");
     274               0 :         pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
     275                 :                           progname);
     276               0 :         exit(1);
     277                 :     }
     278                 : #endif
     279 ECB             : 
     280 GIC          17 :     get_restricted_token();
     281 EUB             : 
     282                 :     /* Set mask based on PGDATA permissions */
     283 GIC          17 :     if (!GetDataDirectoryCreatePerm(datadir_target))
     284 UBC           0 :         pg_fatal("could not read permissions of directory \"%s\": %m",
     285                 :                  datadir_target);
     286                 : 
     287 GIC          17 :     umask(pg_mode_mask);
     288 ECB             : 
     289 GIC          17 :     getRestoreCommand(argv[0]);
     290                 : 
     291 CBC          17 :     atexit(disconnect_atexit);
     292 EUB             : 
     293                 :     /*
     294                 :      * Ok, we have all the options and we're ready to start. First, connect to
     295 ECB             :      * remote server.
     296                 :      */
     297 CBC          17 :     if (connstr_source)
     298                 :     {
     299               6 :         conn = PQconnectdb(connstr_source);
     300                 : 
     301 GIC           6 :         if (PQstatus(conn) == CONNECTION_BAD)
     302 UIC           0 :             pg_fatal("%s", PQerrorMessage(conn));
     303                 : 
     304 GIC           6 :         if (showprogress)
     305 LBC           0 :             pg_log_info("connected to server");
     306                 : 
     307 CBC           6 :         source = init_libpq_source(conn);
     308                 :     }
     309 ECB             :     else
     310 GBC          11 :         source = init_local_source(datadir_source);
     311                 : 
     312 ECB             :     /*
     313 EUB             :      * Check the status of the target instance.
     314                 :      *
     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                 :      */
     322 GIC          17 :     buffer = slurpFile(datadir_target, "global/pg_control", &size);
     323              17 :     digestControlFile(&ControlFile_target, buffer, size);
     324              17 :     pg_free(buffer);
     325                 : 
     326              17 :     if (!no_ensure_shutdown &&
     327              14 :         ControlFile_target.state != DB_SHUTDOWNED &&
     328              11 :         ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY)
     329                 :     {
     330 CBC          10 :         ensureCleanShutdown(argv[0]);
     331 ECB             : 
     332 CBC           9 :         buffer = slurpFile(datadir_target, "global/pg_control", &size);
     333 GIC           9 :         digestControlFile(&ControlFile_target, buffer, size);
     334 CBC           9 :         pg_free(buffer);
     335 ECB             :     }
     336                 : 
     337 GIC          16 :     buffer = source->fetch_file(source, "global/pg_control", &size);
     338 CBC          16 :     digestControlFile(&ControlFile_source, buffer, size);
     339 GIC          16 :     pg_free(buffer);
     340 ECB             : 
     341 CBC          16 :     sanityChecks();
     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                 :      */
     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.
     360 ECB             :      *
     361                 :      * If both clusters are already on the same timeline, there's nothing to
     362                 :      * do.
     363                 :      */
     364 GNC          14 :     if (target_tli == source_tli)
     365                 :     {
     366 GIC           1 :         pg_log_info("source and target cluster are on the same timeline");
     367               1 :         rewind_needed = false;
     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                 :          */
     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);
     386 ECB             : 
     387 GIC          13 :         pg_log_info("servers diverged at WAL location %X/%X on timeline %u",
     388                 :                     LSN_FORMAT_ARGS(divergerec),
     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                 :          */
     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.)
     405 ECB             :          */
     406                 : 
     407                 :         /* read the checkpoint record on the target to see where it ends. */
     408 CBC          13 :         chkptendrec = readOneRecord(datadir_target,
     409 ECB             :                                     ControlFile_target.checkPoint,
     410                 :                                     targetNentries - 1,
     411                 :                                     restore_command);
     412                 : 
     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                 :         }
     421 ECB             : 
     422                 :         /*
     423                 :          * Check for the possibility that the target is in fact a direct
     424                 :          * ancestor of the source. In that case, there is no divergent history
     425                 :          * in the target that needs rewinding.
     426                 :          */
     427 GIC          13 :         if (target_wal_endrec > divergerec)
     428 ECB             :         {
     429 GIC          13 :             rewind_needed = true;
     430                 :         }
     431                 :         else
     432                 :         {
     433                 :             /* the last common checkpoint record must be part of target WAL */
     434 UIC           0 :             Assert(target_wal_endrec == divergerec);
     435                 : 
     436 LBC           0 :             rewind_needed = false;
     437                 :         }
     438                 :     }
     439                 : 
     440 GIC          14 :     if (!rewind_needed)
     441                 :     {
     442               1 :         pg_log_info("no rewind required");
     443               1 :         if (writerecoveryconf && !dry_run)
     444 UIC           0 :             WriteRecoveryConfig(conn, datadir_target,
     445                 :                                 GenerateRecoveryConfig(conn, NULL));
     446 GIC           1 :         exit(0);
     447                 :     }
     448                 : 
     449 CBC          13 :     findLastCheckpoint(datadir_target, divergerec, lastcommontliIndex,
     450                 :                        &chkptrec, &chkpttli, &chkptredo, restore_command);
     451 GIC          13 :     pg_log_info("rewinding from last common checkpoint at %X/%X on timeline %u",
     452                 :                 LSN_FORMAT_ARGS(chkptrec), chkpttli);
     453                 : 
     454 ECB             :     /* Initialize the hash table to track the status of each file */
     455 GIC          13 :     filehash_init();
     456 ECB             : 
     457                 :     /*
     458                 :      * Collect information about all files in the both data directories.
     459                 :      */
     460 CBC          13 :     if (showprogress)
     461 UIC           0 :         pg_log_info("reading source file list");
     462 GIC          13 :     source->traverse_files(source, &process_source_file);
     463                 : 
     464              13 :     if (showprogress)
     465 UIC           0 :         pg_log_info("reading target file list");
     466 GIC          13 :     traverse_datadir(datadir_target, &process_target_file);
     467                 : 
     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                 :      */
     473 GIC          13 :     if (showprogress)
     474 UIC           0 :         pg_log_info("reading WAL in target");
     475 GBC          13 :     extractPageMap(datadir_target, chkptrec, lastcommontliIndex,
     476                 :                    target_wal_endrec, restore_command);
     477 EUB             : 
     478                 :     /*
     479                 :      * We have collected all information we need from both systems. Decide
     480                 :      * what to do with each file.
     481 ECB             :      */
     482 GIC          13 :     filemap = decide_file_actions();
     483 CBC          13 :     if (showprogress)
     484 LBC           0 :         calculate_totals(filemap);
     485 EUB             : 
     486                 :     /* this is too verbose even for verbose mode */
     487 CBC          13 :     if (debug)
     488 GIC          13 :         print_filemap(filemap);
     489                 : 
     490 ECB             :     /*
     491                 :      * Ok, we're ready to start copying things over.
     492                 :      */
     493 GIC          13 :     if (showprogress)
     494                 :     {
     495 UIC           0 :         pg_log_info("need to copy %lu MB (total source directory size is %lu MB)",
     496 ECB             :                     (unsigned long) (filemap->fetch_size / (1024 * 1024)),
     497                 :                     (unsigned long) (filemap->total_size / (1024 * 1024)));
     498                 : 
     499 UIC           0 :         fetch_size = filemap->fetch_size;
     500               0 :         fetch_done = 0;
     501 ECB             :     }
     502 EUB             : 
     503 ECB             :     /*
     504                 :      * We have now collected all the information we need from both systems,
     505                 :      * and we are ready to start modifying the target directory.
     506 EUB             :      *
     507 ECB             :      * This is the point of no return. Once we start copying things, there is
     508                 :      * no turning back!
     509                 :      */
     510 GIC          13 :     perform_rewind(filemap, source, chkptrec, chkpttli, chkptredo);
     511                 : 
     512              12 :     if (showprogress)
     513 UIC           0 :         pg_log_info("syncing target data directory");
     514 CBC          12 :     sync_target_dir();
     515 EUB             : 
     516 ECB             :     /* Also update the standby configuration, if requested. */
     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);
     523 CBC          12 :     if (conn)
     524 ECB             :     {
     525 GBC           6 :         PQfinish(conn);
     526 GIC           6 :         conn = NULL;
     527                 :     }
     528 ECB             : 
     529 CBC          12 :     pg_log_info("Done!");
     530                 : 
     531 GIC          12 :     return 0;
     532                 : }
     533                 : 
     534 ECB             : /*
     535                 :  * Perform the rewind.
     536 EUB             :  *
     537                 :  * We have already collected all the information we need from the
     538                 :  * target and the source.
     539                 :  */
     540                 : static void
     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;
     551 ECB             : 
     552                 :     /*
     553                 :      * Execute the actions in the file map, fetching data from the source
     554 EUB             :      * system as needed.
     555 ECB             :      */
     556 GIC       14832 :     for (int i = 0; i < filemap->nentries; i++)
     557                 :     {
     558 CBC       14820 :         file_entry_t *entry = filemap->entries[i];
     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                 :          */
     565 GIC       14820 :         if (entry->target_pages_to_overwrite.bitmapsize > 0)
     566 ECB             :         {
     567                 :             datapagemap_iterator_t *iter;
     568                 :             BlockNumber blkno;
     569                 :             off_t       offset;
     570                 : 
     571 GIC         390 :             iter = datapagemap_iterate(&entry->target_pages_to_overwrite);
     572 CBC        2027 :             while (datapagemap_next(iter, &blkno))
     573                 :             {
     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                 :         {
     582 CBC        9923 :             case FILE_ACTION_NONE:
     583                 :                 /* nothing else to do */
     584 GIC        9923 :                 break;
     585                 : 
     586            4180 :             case FILE_ACTION_COPY:
     587            4180 :                 source->queue_fetch_file(source, entry->path, entry->source_size);
     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,
     597 CBC           5 :                                           entry->source_size - entry->target_size);
     598 GIC           5 :                 break;
     599 ECB             : 
     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);
     606 CBC           8 :                 break;
     607                 : 
     608 UIC           0 :             case FILE_ACTION_UNDECIDED:
     609               0 :                 pg_fatal("no action decided for file \"%s\"", entry->path);
     610                 :                 break;
     611                 :         }
     612 ECB             :     }
     613                 : 
     614                 :     /* Complete any remaining range-fetches that we queued up above. */
     615 CBC          12 :     source->finish_fetch(source);
     616 ECB             : 
     617 GIC          12 :     close_target_file();
     618 ECB             : 
     619 GIC          12 :     progress_report(true);
     620                 : 
     621 ECB             :     /*
     622                 :      * Fetch the control file from the source last. This ensures that the
     623                 :      * minRecoveryPoint is up-to-date.
     624                 :      */
     625 CBC          12 :     buffer = source->fetch_file(source, "global/pg_control", &size);
     626 GIC          12 :     digestControlFile(&ControlFile_source_after, buffer, size);
     627 CBC          12 :     pg_free(buffer);
     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                 :      */
     637 CBC          12 :     if (datadir_source &&
     638               6 :         memcmp(&ControlFile_source, &ControlFile_source_after,
     639 ECB             :                sizeof(ControlFileData)) != 0)
     640                 :     {
     641 LBC           0 :         pg_fatal("source system was modified while pg_rewind was running");
     642 ECB             :     }
     643                 : 
     644 GIC          12 :     if (showprogress)
     645 LBC           0 :         pg_log_info("creating backup label and updating control file");
     646 ECB             : 
     647                 :     /*
     648                 :      * Create a backup label file, to tell the target where to begin the WAL
     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                 :      *
     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                 :      */
     660 CBC          12 :     if (ControlFile_source.checkPointCopy.redo < chkptredo)
     661                 :     {
     662 GIC           2 :         chkptredo = ControlFile_source.checkPointCopy.redo;
     663               2 :         chkpttli = ControlFile_source.checkPointCopy.ThisTimeLineID;
     664               2 :         chkptrec = ControlFile_source.checkPoint;
     665                 :     }
     666 CBC          12 :     createBackupLabel(chkptredo, chkpttli, chkptrec);
     667 ECB             : 
     668                 :     /*
     669                 :      * Update control file of target, to tell the target how far it must
     670                 :      * replay the WAL (minRecoveryPoint).
     671                 :      */
     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.
     678 ECB             :          */
     679 CBC           6 :         if (ControlFile_source_after.state == DB_IN_ARCHIVE_RECOVERY)
     680                 :         {
     681                 :             /*
     682 EUB             :              * Source is a standby server. We must replay to its
     683                 :              * minRecoveryPoint.
     684                 :              */
     685 CBC           1 :             endrec = ControlFile_source_after.minRecoveryPoint;
     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                 :              */
     694 GIC           5 :             if (ControlFile_source_after.state != DB_IN_PRODUCTION)
     695 UIC           0 :                 pg_fatal("source system was in unexpected state at end of rewind");
     696                 : 
     697 GIC           5 :             endrec = source->get_current_wal_insert_lsn(source);
     698 GNC           5 :             endtli = Max(ControlFile_source_after.checkPointCopy.ThisTimeLineID,
     699                 :                          ControlFile_source_after.minRecoveryPointTLI);
     700                 :         }
     701                 :     }
     702 ECB             :     else
     703                 :     {
     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                 :          */
     708 CBC           6 :         endrec = ControlFile_source_after.checkPoint;
     709 GIC           6 :         endtli = ControlFile_source_after.checkPointCopy.ThisTimeLineID;
     710                 :     }
     711                 : 
     712              12 :     memcpy(&ControlFile_new, &ControlFile_source_after, sizeof(ControlFileData));
     713              12 :     ControlFile_new.minRecoveryPoint = endrec;
     714 CBC          12 :     ControlFile_new.minRecoveryPointTLI = endtli;
     715 GIC          12 :     ControlFile_new.state = DB_IN_ARCHIVE_RECOVERY;
     716              12 :     if (!dry_run)
     717              11 :         update_controlfile(datadir_target, &ControlFile_new, do_sync);
     718              12 : }
     719                 : 
     720                 : static void
     721 CBC          16 : sanityChecks(void)
     722                 : {
     723                 :     /* TODO Check that there's no backup_label in either cluster */
     724                 : 
     725                 :     /* Check system_identifier match */
     726 GIC          16 :     if (ControlFile_target.system_identifier != ControlFile_source.system_identifier)
     727 LBC           0 :         pg_fatal("source and target clusters are from different systems");
     728 ECB             : 
     729                 :     /* check version */
     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                 :     {
     735 UIC           0 :         pg_fatal("clusters are not compatible with this version of pg_rewind");
     736 ECB             :     }
     737 EUB             : 
     738                 :     /*
     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                 :      */
     742 GIC          16 :     if (ControlFile_target.data_checksum_version != PG_DATA_CHECKSUM_VERSION &&
     743              16 :         !ControlFile_target.wal_log_hints)
     744                 :     {
     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
     750 ECB             :      * someone starting the cluster concurrently. Also, this is probably more
     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                 :      */
     754 CBC          16 :     if (ControlFile_target.state != DB_SHUTDOWNED &&
     755               2 :         ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY)
     756               1 :         pg_fatal("target server must be shut down cleanly");
     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                 :      */
     763 CBC          15 :     if (datadir_source &&
     764 GIC           9 :         ControlFile_source.state != DB_SHUTDOWNED &&
     765               2 :         ControlFile_source.state != DB_SHUTDOWNED_IN_RECOVERY)
     766               1 :         pg_fatal("source data directory must be shut down cleanly");
     767              14 : }
     768 ECB             : 
     769 EUB             : /*
     770                 :  * Print a progress report based on the fetch_size and fetch_done variables.
     771                 :  *
     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.
     777 EUB             :  */
     778                 : void
     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];
     784 ECB             :     char        fetch_size_str[32];
     785                 :     pg_time_t   now;
     786                 : 
     787 GBC       49126 :     if (!showprogress)
     788 GIC       49126 :         return;
     789                 : 
     790 UIC           0 :     now = time(NULL);
     791               0 :     if (now == last_progress_report && !finished)
     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;
     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                 :      */
     803 UIC           0 :     if (percent > 100)
     804               0 :         percent = 100;
     805 LBC           0 :     if (fetch_done > fetch_size)
     806               0 :         fetch_size = fetch_done;
     807 ECB             : 
     808 LBC           0 :     snprintf(fetch_done_str, sizeof(fetch_done_str), UINT64_FORMAT,
     809 ECB             :              fetch_done / 1024);
     810 UIC           0 :     snprintf(fetch_size_str, sizeof(fetch_size_str), UINT64_FORMAT,
     811                 :              fetch_size / 1024);
     812                 : 
     813               0 :     fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
     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                 :      */
     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                 :  */
     829 ECB             : static XLogRecPtr
     830 CBC          13 : MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
     831                 : {
     832 GBC          13 :     if (XLogRecPtrIsInvalid(a))
     833               1 :         return b;
     834              12 :     else if (XLogRecPtrIsInvalid(b))
     835 GIC          12 :         return a;
     836 EUB             :     else
     837 UBC           0 :         return Min(a, b);
     838                 : }
     839                 : 
     840                 : /*
     841                 :  * Retrieve timeline history for the source or target system.
     842                 :  */
     843                 : static TimeLineHistoryEntry *
     844 GNC          26 : getTimelineHistory(TimeLineID tli, bool is_source, int *nentries)
     845 EUB             : {
     846                 :     TimeLineHistoryEntry *history;
     847                 : 
     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                 :      */
     852 GBC          26 :     if (tli == 1)
     853                 :     {
     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                 :     }
     859 EUB             :     else
     860                 :     {
     861                 :         char        path[MAXPGPATH];
     862                 :         char       *histfile;
     863                 : 
     864 GIC          14 :         TLHistoryFilePath(path, tli);
     865                 : 
     866                 :         /* Get history file from appropriate source */
     867 GNC          14 :         if (is_source)
     868 CBC          12 :             histfile = source->fetch_file(source, path, NULL);
     869 ECB             :         else
     870 GNC           2 :             histfile = slurpFile(datadir_target, path, NULL);
     871 ECB             : 
     872 GIC          14 :         history = rewind_parseTimeLineHistory(histfile, tli, nentries);
     873 GBC          14 :         pg_free(histfile);
     874                 :     }
     875                 : 
     876 GIC          26 :     if (debug)
     877                 :     {
     878                 :         int         i;
     879                 : 
     880 GNC          26 :         if (is_source)
     881 GIC          13 :             pg_log_debug("Source timeline history:");
     882                 :         else
     883 GNC          13 :             pg_log_debug("Target timeline history:");
     884                 : 
     885                 :         /*
     886 ECB             :          * Print the target timeline history.
     887                 :          */
     888 CBC          41 :         for (i = 0; i < targetNentries; i++)
     889 ECB             :         {
     890                 :             TimeLineHistoryEntry *entry;
     891                 : 
     892 GIC          15 :             entry = &history[i];
     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                 :     }
     898 ECB             : 
     899 GIC          26 :     return history;
     900                 : }
     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
     909 GNC          13 : findCommonAncestorTimeline(TimeLineHistoryEntry *a_history, int a_nentries,
     910                 :                            TimeLineHistoryEntry *b_history, int b_nentries,
     911                 :                            XLogRecPtr *recptr, int *tliIndex)
     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                 :      */
     924 GNC          13 :     n = Min(a_nentries, b_nentries);
     925 GIC          27 :     for (i = 0; i < n; i++)
     926                 :     {
     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                 : 
     932 GIC          13 :     if (i > 0)
     933                 :     {
     934 CBC          13 :         i--;
     935 GNC          13 :         *recptr = MinXLogRecPtr(a_history[i].end, b_history[i].end);
     936 GIC          13 :         *tliIndex = i;
     937              13 :         return;
     938                 :     }
     939                 :     else
     940                 :     {
     941 UIC           0 :         pg_fatal("could not find common ancestor of the source and target cluster's timelines");
     942                 :     }
     943                 : }
     944                 : 
     945                 : 
     946                 : /*
     947 ECB             :  * Create a backup_label file that forces recovery to begin at the last common
     948                 :  * checkpoint.
     949                 :  */
     950                 : static void
     951 CBC          12 : createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpointloc)
     952                 : {
     953                 :     XLogSegNo   startsegno;
     954                 :     time_t      stamp_time;
     955 ECB             :     char        strfbuf[128];
     956                 :     char        xlogfilename[MAXFNAMELEN];
     957                 :     struct tm  *tmp;
     958                 :     char        buf[1000];
     959                 :     int         len;
     960                 : 
     961 GIC          12 :     XLByteToSeg(startpoint, startsegno, WalSegSz);
     962              12 :     XLogFileName(xlogfilename, starttli, startsegno, WalSegSz);
     963                 : 
     964 EUB             :     /*
     965                 :      * Construct backup label file
     966                 :      */
     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"
     974 ECB             :                    "BACKUP METHOD: pg_rewind\n"
     975                 :                    "BACKUP FROM: standby\n"
     976                 :                    "START TIME: %s\n",
     977                 :     /* omit LABEL: line */
     978 GIC          12 :                    LSN_FORMAT_ARGS(startpoint), xlogfilename,
     979              12 :                    LSN_FORMAT_ARGS(checkpointloc),
     980                 :                    strfbuf);
     981              12 :     if (len >= sizeof(buf))
     982 UIC           0 :         pg_fatal("backup label buffer too small");    /* shouldn't happen */
     983                 : 
     984 ECB             :     /* TODO: move old file out of the way, if any. */
     985 CBC          12 :     open_target_file("backup_label", true); /* BACKUP_LABEL_FILE */
     986 GIC          12 :     write_target_range(buf, 0, len);
     987              12 :     close_target_file();
     988              12 : }
     989                 : 
     990 ECB             : /*
     991                 :  * Check CRC of control file
     992                 :  */
     993                 : static void
     994 CBC          54 : checkControlFile(ControlFileData *ControlFile)
     995                 : {
     996                 :     pg_crc32c   crc;
     997                 : 
     998                 :     /* Calculate CRC */
     999 GIC          54 :     INIT_CRC32C(crc);
    1000              54 :     COMP_CRC32C(crc, (char *) ControlFile, offsetof(ControlFileData, crc));
    1001 CBC          54 :     FIN_CRC32C(crc);
    1002 ECB             : 
    1003                 :     /* And simply compare it */
    1004 CBC          54 :     if (!EQ_CRC32C(crc, ControlFile->crc))
    1005 UBC           0 :         pg_fatal("unexpected control file CRC");
    1006 GIC          54 : }
    1007                 : 
    1008 ECB             : /*
    1009                 :  * Verify control file contents in the buffer 'content', and copy it to
    1010                 :  * *ControlFile.
    1011                 :  */
    1012                 : static void
    1013 GIC          54 : digestControlFile(ControlFileData *ControlFile, const char *content,
    1014                 :                   size_t size)
    1015                 : {
    1016              54 :     if (size != PG_CONTROL_FILE_SIZE)
    1017 LBC           0 :         pg_fatal("unexpected control file size %d, expected %d",
    1018                 :                  (int) size, PG_CONTROL_FILE_SIZE);
    1019                 : 
    1020 GIC          54 :     memcpy(ControlFile, content, sizeof(ControlFileData));
    1021                 : 
    1022 ECB             :     /* set and validate WalSegSz */
    1023 CBC          54 :     WalSegSz = ControlFile->xlog_seg_size;
    1024 ECB             : 
    1025 GIC          54 :     if (!IsValidWalSegSize(WalSegSz))
    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",
    1027 ECB             :                           "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes",
    1028 EUB             :                           WalSegSz),
    1029 ECB             :                  WalSegSz);
    1030                 : 
    1031                 :     /* Additional checks on control file */
    1032 GIC          54 :     checkControlFile(ControlFile);
    1033              54 : }
    1034                 : 
    1035                 : /*
    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.
    1040 EUB             :  */
    1041                 : static void
    1042 GIC          17 : getRestoreCommand(const char *argv0)
    1043 ECB             : {
    1044                 :     int         rc;
    1045                 :     char        postgres_exec_path[MAXPGPATH],
    1046                 :                 cmd_output[MAXPGPATH];
    1047                 :     PQExpBuffer postgres_cmd;
    1048                 : 
    1049 GBC          17 :     if (!restore_wal)
    1050 GIC          16 :         return;
    1051                 : 
    1052                 :     /* find postgres executable */
    1053               1 :     rc = find_other_exec(argv0, "postgres",
    1054                 :                          PG_BACKEND_VERSIONSTR,
    1055 ECB             :                          postgres_exec_path);
    1056                 : 
    1057 GIC           1 :     if (rc < 0)
    1058                 :     {
    1059                 :         char        full_path[MAXPGPATH];
    1060                 : 
    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)
    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
    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                 : 
    1072 ECB             :     /*
    1073                 :      * Build a command able to retrieve the value of GUC parameter
    1074                 :      * restore_command, if set.
    1075                 :      */
    1076 CBC           1 :     postgres_cmd = createPQExpBuffer();
    1077                 : 
    1078                 :     /* path to postgres, properly quoted */
    1079 GIC           1 :     appendShellString(postgres_cmd, postgres_exec_path);
    1080 ECB             : 
    1081                 :     /* add -D switch, with properly quoted data directory */
    1082 GIC           1 :     appendPQExpBufferStr(postgres_cmd, " -D ");
    1083               1 :     appendShellString(postgres_cmd, datadir_target);
    1084 EUB             : 
    1085                 :     /* add custom configuration file only if requested */
    1086 GIC           1 :     if (config_file != NULL)
    1087 EUB             :     {
    1088 GBC           1 :         appendPQExpBufferStr(postgres_cmd, " -c config_file=");
    1089 GIC           1 :         appendShellString(postgres_cmd, config_file);
    1090                 :     }
    1091 EUB             : 
    1092                 :     /* add -C switch, for restore_command */
    1093 GIC           1 :     appendPQExpBufferStr(postgres_cmd, " -C restore_command");
    1094                 : 
    1095               1 :     if (!pipe_read_line(postgres_cmd->data, cmd_output, sizeof(cmd_output)))
    1096 UIC           0 :         exit(1);
    1097                 : 
    1098 GIC           1 :     (void) pg_strip_crlf(cmd_output);
    1099 ECB             : 
    1100 GIC           1 :     if (strcmp(cmd_output, "") == 0)
    1101 UIC           0 :         pg_fatal("restore_command is not set in the target cluster");
    1102 ECB             : 
    1103 GIC           1 :     restore_command = pg_strdup(cmd_output);
    1104                 : 
    1105 CBC           1 :     pg_log_debug("using for rewind restore_command = \'%s\'",
    1106 ECB             :                  restore_command);
    1107                 : 
    1108 GIC           1 :     destroyPQExpBuffer(postgres_cmd);
    1109 ECB             : }
    1110                 : 
    1111                 : 
    1112                 : /*
    1113                 :  * Ensure clean shutdown of target instance by launching single-user mode
    1114                 :  * postgres to do crash recovery.
    1115                 :  */
    1116                 : static void
    1117 GIC          10 : ensureCleanShutdown(const char *argv0)
    1118 ECB             : {
    1119 EUB             :     int         ret;
    1120                 : #define MAXCMDLEN (2 * MAXPGPATH)
    1121 ECB             :     char        exec_path[MAXPGPATH];
    1122                 :     PQExpBuffer postgres_cmd;
    1123                 : 
    1124 EUB             :     /* locate postgres binary */
    1125 GIC          10 :     if ((ret = find_other_exec(argv0, "postgres",
    1126 ECB             :                                PG_BACKEND_VERSIONSTR,
    1127                 :                                exec_path)) < 0)
    1128                 :     {
    1129                 :         char        full_path[MAXPGPATH];
    1130                 : 
    1131 LBC           0 :         if (find_my_exec(argv0, full_path) < 0)
    1132 UIC           0 :             strlcpy(full_path, progname, sizeof(full_path));
    1133                 : 
    1134               0 :         if (ret == -1)
    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);
    1140 ECB             :     }
    1141                 : 
    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.
    1148 ECB             :      */
    1149 GIC          10 :     if (dry_run)
    1150 UIC           0 :         return;
    1151                 : 
    1152                 :     /*
    1153                 :      * Finally run postgres in single-user mode.  There is no need to use
    1154 EUB             :      * fsync here.  This makes the recovery faster, and the target data folder
    1155                 :      * is synced at the end anyway.
    1156                 :      */
    1157 GBC          10 :     postgres_cmd = createPQExpBuffer();
    1158 EUB             : 
    1159                 :     /* path to postgres, properly quoted */
    1160 GIC          10 :     appendShellString(postgres_cmd, exec_path);
    1161 EUB             : 
    1162                 :     /* add set of options with properly quoted data directory */
    1163 GIC          10 :     appendPQExpBufferStr(postgres_cmd, " --single -F -D ");
    1164              10 :     appendShellString(postgres_cmd, datadir_target);
    1165 ECB             : 
    1166                 :     /* add custom configuration file only if requested */
    1167 GIC          10 :     if (config_file != NULL)
    1168                 :     {
    1169               9 :         appendPQExpBufferStr(postgres_cmd, " -c config_file=");
    1170               9 :         appendShellString(postgres_cmd, config_file);
    1171                 :     }
    1172 ECB             : 
    1173 EUB             :     /* finish with the database name, and a properly quoted redirection */
    1174 GIC          10 :     appendPQExpBufferStr(postgres_cmd, " template1 < ");
    1175              10 :     appendShellString(postgres_cmd, DEVNULL);
    1176                 : 
    1177 GNC          10 :     fflush(NULL);
    1178 GIC          10 :     if (system(postgres_cmd->data) != 0)
    1179                 :     {
    1180               1 :         pg_log_error("postgres single-user mode in target cluster failed");
    1181 CBC           1 :         pg_log_error_detail("Command was: %s", postgres_cmd->data);
    1182 GIC           1 :         exit(1);
    1183                 :     }
    1184 ECB             : 
    1185 GIC           9 :     destroyPQExpBuffer(postgres_cmd);
    1186                 : }
    1187 ECB             : 
    1188                 : static void
    1189 GIC          17 : disconnect_atexit(void)
    1190                 : {
    1191 CBC          17 :     if (conn != NULL)
    1192 UIC           0 :         PQfinish(conn);
    1193 CBC          17 : }
        

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