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