]> granicus.if.org Git - postgresql/blob - contrib/pg_standby/pg_standby.c
Replace the XLogInsert slots with regular LWLocks.
[postgresql] / contrib / pg_standby / pg_standby.c
1 /*
2  * contrib/pg_standby/pg_standby.c
3  *
4  *
5  * pg_standby.c
6  *
7  * Production-ready example of how to create a Warm Standby
8  * database server using continuous archiving as a
9  * replication mechanism
10  *
11  * We separate the parameters for archive and nextWALfile
12  * so that we can check the archive exists, even if the
13  * WAL file doesn't (yet).
14  *
15  * This program will be executed once in full for each file
16  * requested by the warm standby server.
17  *
18  * It is designed to cater to a variety of needs, as well
19  * providing a customizable section.
20  *
21  * Original author:             Simon Riggs  simon@2ndquadrant.com
22  * Current maintainer:  Simon Riggs
23  */
24 #include "postgres_fe.h"
25
26 #include <ctype.h>
27 #include <dirent.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <signal.h>
31 #include <sys/time.h>
32
33 #include "pg_getopt.h"
34
35 const char *progname;
36
37 /* Options and defaults */
38 int                     sleeptime = 5;          /* amount of time to sleep between file checks */
39 int                     waittime = -1;          /* how long we have been waiting, -1 no wait
40                                                                  * yet */
41 int                     maxwaittime = 0;        /* how long are we prepared to wait for? */
42 int                     keepfiles = 0;          /* number of WAL files to keep, 0 keep all */
43 int                     maxretries = 3;         /* number of retries on restore command */
44 bool            debug = false;          /* are we debugging? */
45 bool            need_cleanup = false;           /* do we need to remove files from
46                                                                                  * archive? */
47
48 #ifndef WIN32
49 static volatile sig_atomic_t signaled = false;
50 #endif
51
52 char       *archiveLocation;    /* where to find the archive? */
53 char       *triggerPath;                /* where to find the trigger file? */
54 char       *xlogFilePath;               /* where we are going to restore to */
55 char       *nextWALFileName;    /* the file we need to get from archive */
56 char       *restartWALFileName; /* the file from which we can restart restore */
57 char       *priorWALFileName;   /* the file we need to get from archive */
58 char            WALFilePath[MAXPGPATH];         /* the file path including archive */
59 char            restoreCommand[MAXPGPATH];      /* run this to restore */
60 char            exclusiveCleanupFileName[MAXPGPATH];            /* the file we need to
61                                                                                                                  * get from archive */
62
63 /*
64  * Two types of failover are supported (smart and fast failover).
65  *
66  * The content of the trigger file determines the type of failover. If the
67  * trigger file contains the word "smart" (or the file is empty), smart
68  * failover is chosen: pg_standby acts as cp or ln command itself, on
69  * successful completion all the available WAL records will be applied
70  * resulting in zero data loss. But, it might take a long time to finish
71  * recovery if there's a lot of unapplied WAL.
72  *
73  * On the other hand, if the trigger file contains the word "fast", the
74  * recovery is finished immediately even if unapplied WAL files remain. Any
75  * transactions in the unapplied WAL files are lost.
76  *
77  * An empty trigger file performs smart failover. SIGUSR or SIGINT triggers
78  * fast failover. A timeout causes fast failover (smart failover would have
79  * the same effect, since if the timeout is reached there is no unapplied WAL).
80  */
81 #define NoFailover              0
82 #define SmartFailover   1
83 #define FastFailover    2
84
85 static int      Failover = NoFailover;
86
87 #define RESTORE_COMMAND_COPY 0
88 #define RESTORE_COMMAND_LINK 1
89 int                     restoreCommandType;
90
91 #define XLOG_DATA                        0
92 #define XLOG_HISTORY             1
93 #define XLOG_BACKUP_LABEL        2
94 int                     nextWALFileType;
95
96 #define SET_RESTORE_COMMAND(cmd, arg1, arg2) \
97         snprintf(restoreCommand, MAXPGPATH, cmd " \"%s\" \"%s\"", arg1, arg2)
98
99 struct stat stat_buf;
100
101 /* =====================================================================
102  *
103  *                Customizable section
104  *
105  * =====================================================================
106  *
107  *      Currently, this section assumes that the Archive is a locally
108  *      accessible directory. If you want to make other assumptions,
109  *      such as using a vendor-specific archive and access API, these
110  *      routines are the ones you'll need to change. You're
111  *      encouraged to submit any changes to pgsql-hackers@postgresql.org
112  *      or personally to the current maintainer. Those changes may be
113  *      folded in to later versions of this program.
114  */
115
116 #define XLOG_DATA_FNAME_LEN             24
117 /* Reworked from access/xlog_internal.h */
118 #define XLogFileName(fname, tli, log, seg)      \
119         snprintf(fname, XLOG_DATA_FNAME_LEN + 1, "%08X%08X%08X", tli, log, seg)
120
121 /*
122  *      Initialize allows customized commands into the warm standby program.
123  *
124  *      As an example, and probably the common case, we use either
125  *      cp/ln commands on *nix, or copy/move command on Windows.
126  */
127 static void
128 CustomizableInitialize(void)
129 {
130 #ifdef WIN32
131         snprintf(WALFilePath, MAXPGPATH, "%s\\%s", archiveLocation, nextWALFileName);
132         switch (restoreCommandType)
133         {
134                 case RESTORE_COMMAND_LINK:
135                         SET_RESTORE_COMMAND("mklink", WALFilePath, xlogFilePath);
136                         break;
137                 case RESTORE_COMMAND_COPY:
138                 default:
139                         SET_RESTORE_COMMAND("copy", WALFilePath, xlogFilePath);
140                         break;
141         }
142 #else
143         snprintf(WALFilePath, MAXPGPATH, "%s/%s", archiveLocation, nextWALFileName);
144         switch (restoreCommandType)
145         {
146                 case RESTORE_COMMAND_LINK:
147 #if HAVE_WORKING_LINK
148                         SET_RESTORE_COMMAND("ln -s -f", WALFilePath, xlogFilePath);
149                         break;
150 #endif
151                 case RESTORE_COMMAND_COPY:
152                 default:
153                         SET_RESTORE_COMMAND("cp", WALFilePath, xlogFilePath);
154                         break;
155         }
156 #endif
157
158         /*
159          * This code assumes that archiveLocation is a directory You may wish to
160          * add code to check for tape libraries, etc.. So, since it is a
161          * directory, we use stat to test if it's accessible
162          */
163         if (stat(archiveLocation, &stat_buf) != 0)
164         {
165                 fprintf(stderr, "%s: archive location \"%s\" does not exist\n", progname, archiveLocation);
166                 fflush(stderr);
167                 exit(2);
168         }
169 }
170
171 /*
172  * CustomizableNextWALFileReady()
173  *
174  *        Is the requested file ready yet?
175  */
176 static bool
177 CustomizableNextWALFileReady()
178 {
179         if (stat(WALFilePath, &stat_buf) == 0)
180         {
181                 /*
182                  * If it's a backup file, return immediately. If it's a regular file
183                  * return only if it's the right size already.
184                  */
185                 if (strlen(nextWALFileName) > 24 &&
186                         strspn(nextWALFileName, "0123456789ABCDEF") == 24 &&
187                 strcmp(nextWALFileName + strlen(nextWALFileName) - strlen(".backup"),
188                            ".backup") == 0)
189                 {
190                         nextWALFileType = XLOG_BACKUP_LABEL;
191                         return true;
192                 }
193                 else if (stat_buf.st_size == XLOG_SEG_SIZE)
194                 {
195 #ifdef WIN32
196
197                         /*
198                          * Windows 'cp' sets the final file size before the copy is
199                          * complete, and not yet ready to be opened by pg_standby. So we
200                          * wait for sleeptime secs before attempting to restore. If that
201                          * is not enough, we will rely on the retry/holdoff mechanism.
202                          * GNUWin32's cp does not have this problem.
203                          */
204                         pg_usleep(sleeptime * 1000000L);
205 #endif
206                         nextWALFileType = XLOG_DATA;
207                         return true;
208                 }
209
210                 /*
211                  * If still too small, wait until it is the correct size
212                  */
213                 if (stat_buf.st_size > XLOG_SEG_SIZE)
214                 {
215                         if (debug)
216                         {
217                                 fprintf(stderr, "file size greater than expected\n");
218                                 fflush(stderr);
219                         }
220                         exit(3);
221                 }
222         }
223
224         return false;
225 }
226
227 #define MaxSegmentsPerLogFile ( 0xFFFFFFFF / XLOG_SEG_SIZE )
228
229 static void
230 CustomizableCleanupPriorWALFiles(void)
231 {
232         /*
233          * Work out name of prior file from current filename
234          */
235         if (nextWALFileType == XLOG_DATA)
236         {
237                 int                     rc;
238                 DIR                *xldir;
239                 struct dirent *xlde;
240
241                 /*
242                  * Assume it's OK to keep failing. The failure situation may change
243                  * over time, so we'd rather keep going on the main processing than
244                  * fail because we couldn't clean up yet.
245                  */
246                 if ((xldir = opendir(archiveLocation)) != NULL)
247                 {
248                         while ((xlde = readdir(xldir)) != NULL)
249                         {
250                                 /*
251                                  * We ignore the timeline part of the XLOG segment identifiers
252                                  * in deciding whether a segment is still needed.  This
253                                  * ensures that we won't prematurely remove a segment from a
254                                  * parent timeline. We could probably be a little more
255                                  * proactive about removing segments of non-parent timelines,
256                                  * but that would be a whole lot more complicated.
257                                  *
258                                  * We use the alphanumeric sorting property of the filenames
259                                  * to decide which ones are earlier than the
260                                  * exclusiveCleanupFileName file. Note that this means files
261                                  * are not removed in the order they were originally written,
262                                  * in case this worries you.
263                                  */
264                                 if (strlen(xlde->d_name) == XLOG_DATA_FNAME_LEN &&
265                                         strspn(xlde->d_name, "0123456789ABCDEF") == XLOG_DATA_FNAME_LEN &&
266                                   strcmp(xlde->d_name + 8, exclusiveCleanupFileName + 8) < 0)
267                                 {
268 #ifdef WIN32
269                                         snprintf(WALFilePath, MAXPGPATH, "%s\\%s", archiveLocation, xlde->d_name);
270 #else
271                                         snprintf(WALFilePath, MAXPGPATH, "%s/%s", archiveLocation, xlde->d_name);
272 #endif
273
274                                         if (debug)
275                                                 fprintf(stderr, "\nremoving file \"%s\"", WALFilePath);
276
277                                         rc = unlink(WALFilePath);
278                                         if (rc != 0)
279                                         {
280                                                 fprintf(stderr, "\n%s: ERROR: could not remove file \"%s\": %s\n",
281                                                                 progname, WALFilePath, strerror(errno));
282                                                 break;
283                                         }
284                                 }
285                         }
286                         if (debug)
287                                 fprintf(stderr, "\n");
288                 }
289                 else
290                         fprintf(stderr, "%s: could not open archive location \"%s\": %s\n",
291                                         progname, archiveLocation, strerror(errno));
292
293                 closedir(xldir);
294                 fflush(stderr);
295         }
296 }
297
298 /* =====================================================================
299  *                End of Customizable section
300  * =====================================================================
301  */
302
303 /*
304  * SetWALFileNameForCleanup()
305  *
306  *        Set the earliest WAL filename that we want to keep on the archive
307  *        and decide whether we need_cleanup
308  */
309 static bool
310 SetWALFileNameForCleanup(void)
311 {
312         uint32          tli = 1,
313                                 log = 0,
314                                 seg = 0;
315         uint32          log_diff = 0,
316                                 seg_diff = 0;
317         bool            cleanup = false;
318
319         if (restartWALFileName)
320         {
321                 /*
322                  * Don't do cleanup if the restartWALFileName provided is later than
323                  * the xlog file requested. This is an error and we must not remove
324                  * these files from archive. This shouldn't happen, but better safe
325                  * than sorry.
326                  */
327                 if (strcmp(restartWALFileName, nextWALFileName) > 0)
328                         return false;
329
330                 strlcpy(exclusiveCleanupFileName, restartWALFileName, sizeof(exclusiveCleanupFileName));
331                 return true;
332         }
333
334         if (keepfiles > 0)
335         {
336                 sscanf(nextWALFileName, "%08X%08X%08X", &tli, &log, &seg);
337                 if (tli > 0 && seg > 0)
338                 {
339                         log_diff = keepfiles / MaxSegmentsPerLogFile;
340                         seg_diff = keepfiles % MaxSegmentsPerLogFile;
341                         if (seg_diff > seg)
342                         {
343                                 log_diff++;
344                                 seg = MaxSegmentsPerLogFile - (seg_diff - seg);
345                         }
346                         else
347                                 seg -= seg_diff;
348
349                         if (log >= log_diff)
350                         {
351                                 log -= log_diff;
352                                 cleanup = true;
353                         }
354                         else
355                         {
356                                 log = 0;
357                                 seg = 0;
358                         }
359                 }
360         }
361
362         XLogFileName(exclusiveCleanupFileName, tli, log, seg);
363
364         return cleanup;
365 }
366
367 /*
368  * CheckForExternalTrigger()
369  *
370  *        Is there a trigger file? Sets global 'Failover' variable to indicate
371  *        what kind of a trigger file it was. A "fast" trigger file is turned
372  *        into a "smart" file as a side-effect.
373  */
374 static void
375 CheckForExternalTrigger(void)
376 {
377         char            buf[32];
378         int                     fd;
379         int                     len;
380
381         /*
382          * Look for a trigger file, if that option has been selected
383          *
384          * We use stat() here because triggerPath is always a file rather than
385          * potentially being in an archive
386          */
387         if (!triggerPath || stat(triggerPath, &stat_buf) != 0)
388                 return;
389
390         /*
391          * An empty trigger file performs smart failover. There's a little race
392          * condition here: if the writer of the trigger file has just created the
393          * file, but not yet written anything to it, we'll treat that as smart
394          * shutdown even if the other process was just about to write "fast" to
395          * it. But that's fine: we'll restore one more WAL file, and when we're
396          * invoked next time, we'll see the word "fast" and fail over immediately.
397          */
398         if (stat_buf.st_size == 0)
399         {
400                 Failover = SmartFailover;
401                 fprintf(stderr, "trigger file found: smart failover\n");
402                 fflush(stderr);
403                 return;
404         }
405
406         if ((fd = open(triggerPath, O_RDWR, 0)) < 0)
407         {
408                 fprintf(stderr, "WARNING: could not open \"%s\": %s\n",
409                                 triggerPath, strerror(errno));
410                 fflush(stderr);
411                 return;
412         }
413
414         if ((len = read(fd, buf, sizeof(buf))) < 0)
415         {
416                 fprintf(stderr, "WARNING: could not read \"%s\": %s\n",
417                                 triggerPath, strerror(errno));
418                 fflush(stderr);
419                 close(fd);
420                 return;
421         }
422         buf[len] = '\0';
423
424         if (strncmp(buf, "smart", 5) == 0)
425         {
426                 Failover = SmartFailover;
427                 fprintf(stderr, "trigger file found: smart failover\n");
428                 fflush(stderr);
429                 close(fd);
430                 return;
431         }
432
433         if (strncmp(buf, "fast", 4) == 0)
434         {
435                 Failover = FastFailover;
436
437                 fprintf(stderr, "trigger file found: fast failover\n");
438                 fflush(stderr);
439
440                 /*
441                  * Turn it into a "smart" trigger by truncating the file. Otherwise if
442                  * the server asks us again to restore a segment that was restored
443                  * already, we would return "not found" and upset the server.
444                  */
445                 if (ftruncate(fd, 0) < 0)
446                 {
447                         fprintf(stderr, "WARNING: could not read \"%s\": %s\n",
448                                         triggerPath, strerror(errno));
449                         fflush(stderr);
450                 }
451                 close(fd);
452
453                 return;
454         }
455         close(fd);
456
457         fprintf(stderr, "WARNING: invalid content in \"%s\"\n", triggerPath);
458         fflush(stderr);
459         return;
460 }
461
462 /*
463  * RestoreWALFileForRecovery()
464  *
465  *        Perform the action required to restore the file from archive
466  */
467 static bool
468 RestoreWALFileForRecovery(void)
469 {
470         int                     rc = 0;
471         int                     numretries = 0;
472
473         if (debug)
474         {
475                 fprintf(stderr, "running restore:      ");
476                 fflush(stderr);
477         }
478
479         while (numretries <= maxretries)
480         {
481                 rc = system(restoreCommand);
482                 if (rc == 0)
483                 {
484                         if (debug)
485                         {
486                                 fprintf(stderr, "OK\n");
487                                 fflush(stderr);
488                         }
489                         return true;
490                 }
491                 pg_usleep(numretries++ * sleeptime * 1000000L);
492         }
493
494         /*
495          * Allow caller to add additional info
496          */
497         if (debug)
498                 fprintf(stderr, "not restored\n");
499         return false;
500 }
501
502 static void
503 usage(void)
504 {
505         printf("%s allows PostgreSQL warm standby servers to be configured.\n\n", progname);
506         printf("Usage:\n");
507         printf("  %s [OPTION]... ARCHIVELOCATION NEXTWALFILE XLOGFILEPATH [RESTARTWALFILE]\n", progname);
508         printf("\nOptions:\n");
509         printf("  -c                 copy file from archive (default)\n");
510         printf("  -d                 generate lots of debugging output (testing only)\n");
511         printf("  -k NUMFILESTOKEEP  if RESTARTWALFILE is not used, remove files prior to limit\n"
512                    "                     (0 keeps all)\n");
513         printf("  -l                 does nothing; use of link is now deprecated\n");
514         printf("  -r MAXRETRIES      max number of times to retry, with progressive wait\n"
515                    "                     (default=3)\n");
516         printf("  -s SLEEPTIME       seconds to wait between file checks (min=1, max=60,\n"
517                    "                     default=5)\n");
518         printf("  -t TRIGGERFILE     trigger file to initiate failover (no default)\n");
519         printf("  -V, --version      output version information, then exit\n");
520         printf("  -w MAXWAITTIME     max seconds to wait for a file (0=no limit) (default=0)\n");
521         printf("  -?, --help         show this help, then exit\n");
522         printf("\n"
523                    "Main intended use as restore_command in recovery.conf:\n"
524                    "  restore_command = 'pg_standby [OPTION]... ARCHIVELOCATION %%f %%p %%r'\n"
525                    "e.g.\n"
526         "  restore_command = 'pg_standby /mnt/server/archiverdir %%f %%p %%r'\n");
527         printf("\nReport bugs to <pgsql-bugs@postgresql.org>.\n");
528 }
529
530 #ifndef WIN32
531 static void
532 sighandler(int sig)
533 {
534         signaled = true;
535 }
536
537 /* We don't want SIGQUIT to core dump */
538 static void
539 sigquit_handler(int sig)
540 {
541         pqsignal(SIGINT, SIG_DFL);
542         kill(getpid(), SIGINT);
543 }
544 #endif
545
546 /*------------ MAIN ----------------------------------------*/
547 int
548 main(int argc, char **argv)
549 {
550         int                     c;
551
552         progname = get_progname(argv[0]);
553
554         if (argc > 1)
555         {
556                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
557                 {
558                         usage();
559                         exit(0);
560                 }
561                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
562                 {
563                         puts("pg_standby (PostgreSQL) " PG_VERSION);
564                         exit(0);
565                 }
566         }
567
568 #ifndef WIN32
569
570         /*
571          * You can send SIGUSR1 to trigger failover.
572          *
573          * Postmaster uses SIGQUIT to request immediate shutdown. The default
574          * action is to core dump, but we don't want that, so trap it and commit
575          * suicide without core dump.
576          *
577          * We used to use SIGINT and SIGQUIT to trigger failover, but that turned
578          * out to be a bad idea because postmaster uses SIGQUIT to request
579          * immediate shutdown. We still trap SIGINT, but that may change in a
580          * future release.
581          *
582          * There's no way to trigger failover via signal on Windows.
583          */
584         (void) pqsignal(SIGUSR1, sighandler);
585         (void) pqsignal(SIGINT, sighandler);            /* deprecated, use SIGUSR1 */
586         (void) pqsignal(SIGQUIT, sigquit_handler);
587 #endif
588
589         while ((c = getopt(argc, argv, "cdk:lr:s:t:w:")) != -1)
590         {
591                 switch (c)
592                 {
593                         case 'c':                       /* Use copy */
594                                 restoreCommandType = RESTORE_COMMAND_COPY;
595                                 break;
596                         case 'd':                       /* Debug mode */
597                                 debug = true;
598                                 break;
599                         case 'k':                       /* keepfiles */
600                                 keepfiles = atoi(optarg);
601                                 if (keepfiles < 0)
602                                 {
603                                         fprintf(stderr, "%s: -k keepfiles must be >= 0\n", progname);
604                                         exit(2);
605                                 }
606                                 break;
607                         case 'l':                       /* Use link */
608
609                                 /*
610                                  * Link feature disabled, possibly permanently. Linking causes
611                                  * a problem after recovery ends that is not currently
612                                  * resolved by PostgreSQL. 25 Jun 2009
613                                  */
614 #ifdef NOT_USED
615                                 restoreCommandType = RESTORE_COMMAND_LINK;
616 #endif
617                                 break;
618                         case 'r':                       /* Retries */
619                                 maxretries = atoi(optarg);
620                                 if (maxretries < 0)
621                                 {
622                                         fprintf(stderr, "%s: -r maxretries must be >= 0\n", progname);
623                                         exit(2);
624                                 }
625                                 break;
626                         case 's':                       /* Sleep time */
627                                 sleeptime = atoi(optarg);
628                                 if (sleeptime <= 0 || sleeptime > 60)
629                                 {
630                                         fprintf(stderr, "%s: -s sleeptime incorrectly set\n", progname);
631                                         exit(2);
632                                 }
633                                 break;
634                         case 't':                       /* Trigger file */
635                                 triggerPath = strdup(optarg);
636                                 break;
637                         case 'w':                       /* Max wait time */
638                                 maxwaittime = atoi(optarg);
639                                 if (maxwaittime < 0)
640                                 {
641                                         fprintf(stderr, "%s: -w maxwaittime incorrectly set\n", progname);
642                                         exit(2);
643                                 }
644                                 break;
645                         default:
646                                 fprintf(stderr, "Try \"%s --help\" for more information.\n", progname);
647                                 exit(2);
648                                 break;
649                 }
650         }
651
652         /*
653          * Parameter checking - after checking to see if trigger file present
654          */
655         if (argc == 1)
656         {
657                 fprintf(stderr, "%s: not enough command-line arguments\n", progname);
658                 exit(2);
659         }
660
661         /*
662          * We will go to the archiveLocation to get nextWALFileName.
663          * nextWALFileName may not exist yet, which would not be an error, so we
664          * separate the archiveLocation and nextWALFileName so we can check
665          * separately whether archiveLocation exists, if not that is an error
666          */
667         if (optind < argc)
668         {
669                 archiveLocation = argv[optind];
670                 optind++;
671         }
672         else
673         {
674                 fprintf(stderr, "%s: must specify archive location\n", progname);
675                 fprintf(stderr, "Try \"%s --help\" for more information.\n", progname);
676                 exit(2);
677         }
678
679         if (optind < argc)
680         {
681                 nextWALFileName = argv[optind];
682                 optind++;
683         }
684         else
685         {
686                 fprintf(stderr, "%s: must specify WAL file name as second non-option argument (use \"%%f\")\n", progname);
687                 fprintf(stderr, "Try \"%s --help\" for more information.\n", progname);
688                 exit(2);
689         }
690
691         if (optind < argc)
692         {
693                 xlogFilePath = argv[optind];
694                 optind++;
695         }
696         else
697         {
698                 fprintf(stderr, "%s: must specify xlog destination as third non-option argument (use \"%%p\")\n", progname);
699                 fprintf(stderr, "Try \"%s --help\" for more information.\n", progname);
700                 exit(2);
701         }
702
703         if (optind < argc)
704         {
705                 restartWALFileName = argv[optind];
706                 optind++;
707         }
708
709         CustomizableInitialize();
710
711         need_cleanup = SetWALFileNameForCleanup();
712
713         if (debug)
714         {
715                 fprintf(stderr, "Trigger file:         %s\n", triggerPath ? triggerPath : "<not set>");
716                 fprintf(stderr, "Waiting for WAL file: %s\n", nextWALFileName);
717                 fprintf(stderr, "WAL file path:        %s\n", WALFilePath);
718                 fprintf(stderr, "Restoring to:         %s\n", xlogFilePath);
719                 fprintf(stderr, "Sleep interval:       %d second%s\n",
720                                 sleeptime, (sleeptime > 1 ? "s" : " "));
721                 fprintf(stderr, "Max wait interval:    %d %s\n",
722                                 maxwaittime, (maxwaittime > 0 ? "seconds" : "forever"));
723                 fprintf(stderr, "Command for restore:  %s\n", restoreCommand);
724                 fprintf(stderr, "Keep archive history: ");
725                 if (need_cleanup)
726                         fprintf(stderr, "%s and later\n", exclusiveCleanupFileName);
727                 else
728                         fprintf(stderr, "no cleanup required\n");
729                 fflush(stderr);
730         }
731
732         /*
733          * Check for initial history file: always the first file to be requested
734          * It's OK if the file isn't there - all other files need to wait
735          */
736         if (strlen(nextWALFileName) > 8 &&
737                 strspn(nextWALFileName, "0123456789ABCDEF") == 8 &&
738                 strcmp(nextWALFileName + strlen(nextWALFileName) - strlen(".history"),
739                            ".history") == 0)
740         {
741                 nextWALFileType = XLOG_HISTORY;
742                 if (RestoreWALFileForRecovery())
743                         exit(0);
744                 else
745                 {
746                         if (debug)
747                         {
748                                 fprintf(stderr, "history file not found\n");
749                                 fflush(stderr);
750                         }
751                         exit(1);
752                 }
753         }
754
755         /*
756          * Main wait loop
757          */
758         for (;;)
759         {
760                 /* Check for trigger file or signal first */
761                 CheckForExternalTrigger();
762 #ifndef WIN32
763                 if (signaled)
764                 {
765                         Failover = FastFailover;
766                         if (debug)
767                         {
768                                 fprintf(stderr, "signaled to exit: fast failover\n");
769                                 fflush(stderr);
770                         }
771                 }
772 #endif
773
774                 /*
775                  * Check for fast failover immediately, before checking if the
776                  * requested WAL file is available
777                  */
778                 if (Failover == FastFailover)
779                         exit(1);
780
781                 if (CustomizableNextWALFileReady())
782                 {
783                         /*
784                          * Once we have restored this file successfully we can remove some
785                          * prior WAL files. If this restore fails we musn't remove any
786                          * file because some of them will be requested again immediately
787                          * after the failed restore, or when we restart recovery.
788                          */
789                         if (RestoreWALFileForRecovery())
790                         {
791                                 if (need_cleanup)
792                                         CustomizableCleanupPriorWALFiles();
793
794                                 exit(0);
795                         }
796                         else
797                         {
798                                 /* Something went wrong in copying the file */
799                                 exit(1);
800                         }
801                 }
802
803                 /* Check for smart failover if the next WAL file was not available */
804                 if (Failover == SmartFailover)
805                         exit(1);
806
807                 if (sleeptime <= 60)
808                         pg_usleep(sleeptime * 1000000L);
809
810                 waittime += sleeptime;
811                 if (waittime >= maxwaittime && maxwaittime > 0)
812                 {
813                         Failover = FastFailover;
814                         if (debug)
815                         {
816                                 fprintf(stderr, "Timed out after %d seconds: fast failover\n",
817                                                 waittime);
818                                 fflush(stderr);
819                         }
820                 }
821                 if (debug)
822                 {
823                         fprintf(stderr, "WAL file not present yet.");
824                         if (triggerPath)
825                                 fprintf(stderr, " Checking for trigger file...");
826                         fprintf(stderr, "\n");
827                         fflush(stderr);
828                 }
829         }
830 }