00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "postgres.h"
00027
00028 #include <fcntl.h>
00029 #include <signal.h>
00030 #include <time.h>
00031 #include <sys/time.h>
00032 #include <sys/wait.h>
00033 #include <unistd.h>
00034
00035 #include "access/xlog.h"
00036 #include "access/xlog_internal.h"
00037 #include "libpq/pqsignal.h"
00038 #include "miscadmin.h"
00039 #include "postmaster/fork_process.h"
00040 #include "postmaster/pgarch.h"
00041 #include "postmaster/postmaster.h"
00042 #include "storage/fd.h"
00043 #include "storage/ipc.h"
00044 #include "storage/latch.h"
00045 #include "storage/pg_shmem.h"
00046 #include "storage/pmsignal.h"
00047 #include "utils/guc.h"
00048 #include "utils/ps_status.h"
00049
00050
00051
00052
00053
00054
00055 #define PGARCH_AUTOWAKE_INTERVAL 60
00056
00057
00058 #define PGARCH_RESTART_INTERVAL 10
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 #define MIN_XFN_CHARS 16
00071 #define MAX_XFN_CHARS 40
00072 #define VALID_XFN_CHARS "0123456789ABCDEF.history.backup"
00073
00074 #define NUM_ARCHIVE_RETRIES 3
00075
00076
00077
00078
00079
00080
00081 static time_t last_pgarch_start_time;
00082 static time_t last_sigterm_time = 0;
00083
00084
00085
00086
00087 static volatile sig_atomic_t got_SIGHUP = false;
00088 static volatile sig_atomic_t got_SIGTERM = false;
00089 static volatile sig_atomic_t wakened = false;
00090 static volatile sig_atomic_t ready_to_stop = false;
00091
00092
00093
00094
00095 static Latch mainloop_latch;
00096
00097
00098
00099
00100
00101 #ifdef EXEC_BACKEND
00102 static pid_t pgarch_forkexec(void);
00103 #endif
00104
00105 NON_EXEC_STATIC void PgArchiverMain(int argc, char *argv[]) __attribute__((noreturn));
00106 static void pgarch_exit(SIGNAL_ARGS);
00107 static void ArchSigHupHandler(SIGNAL_ARGS);
00108 static void ArchSigTermHandler(SIGNAL_ARGS);
00109 static void pgarch_waken(SIGNAL_ARGS);
00110 static void pgarch_waken_stop(SIGNAL_ARGS);
00111 static void pgarch_MainLoop(void);
00112 static void pgarch_ArchiverCopyLoop(void);
00113 static bool pgarch_archiveXlog(char *xlog);
00114 static bool pgarch_readyXlog(char *xlog);
00115 static void pgarch_archiveDone(char *xlog);
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 int
00134 pgarch_start(void)
00135 {
00136 time_t curtime;
00137 pid_t pgArchPid;
00138
00139
00140
00141
00142 if (!XLogArchivingActive())
00143 return 0;
00144
00145
00146
00147
00148
00149
00150
00151 curtime = time(NULL);
00152 if ((unsigned int) (curtime - last_pgarch_start_time) <
00153 (unsigned int) PGARCH_RESTART_INTERVAL)
00154 return 0;
00155 last_pgarch_start_time = curtime;
00156
00157 #ifdef EXEC_BACKEND
00158 switch ((pgArchPid = pgarch_forkexec()))
00159 #else
00160 switch ((pgArchPid = fork_process()))
00161 #endif
00162 {
00163 case -1:
00164 ereport(LOG,
00165 (errmsg("could not fork archiver: %m")));
00166 return 0;
00167
00168 #ifndef EXEC_BACKEND
00169 case 0:
00170
00171
00172 ClosePostmasterPorts(false);
00173
00174
00175 on_exit_reset();
00176
00177
00178 PGSharedMemoryDetach();
00179
00180 PgArchiverMain(0, NULL);
00181 break;
00182 #endif
00183
00184 default:
00185 return (int) pgArchPid;
00186 }
00187
00188
00189 return 0;
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 #ifdef EXEC_BACKEND
00199
00200
00201
00202
00203
00204
00205 static pid_t
00206 pgarch_forkexec(void)
00207 {
00208 char *av[10];
00209 int ac = 0;
00210
00211 av[ac++] = "postgres";
00212
00213 av[ac++] = "--forkarch";
00214
00215 av[ac++] = NULL;
00216
00217 av[ac] = NULL;
00218 Assert(ac < lengthof(av));
00219
00220 return postmaster_forkexec(ac, av);
00221 }
00222 #endif
00223
00224
00225
00226
00227
00228
00229
00230
00231 NON_EXEC_STATIC void
00232 PgArchiverMain(int argc, char *argv[])
00233 {
00234 IsUnderPostmaster = true;
00235
00236 MyProcPid = getpid();
00237
00238 MyStartTime = time(NULL);
00239
00240
00241
00242
00243
00244 #ifdef HAVE_SETSID
00245 if (setsid() < 0)
00246 elog(FATAL, "setsid() failed: %m");
00247 #endif
00248
00249 InitializeLatchSupport();
00250
00251 InitLatch(&mainloop_latch);
00252
00253
00254
00255
00256
00257 pqsignal(SIGHUP, ArchSigHupHandler);
00258 pqsignal(SIGINT, SIG_IGN);
00259 pqsignal(SIGTERM, ArchSigTermHandler);
00260 pqsignal(SIGQUIT, pgarch_exit);
00261 pqsignal(SIGALRM, SIG_IGN);
00262 pqsignal(SIGPIPE, SIG_IGN);
00263 pqsignal(SIGUSR1, pgarch_waken);
00264 pqsignal(SIGUSR2, pgarch_waken_stop);
00265 pqsignal(SIGCHLD, SIG_DFL);
00266 pqsignal(SIGTTIN, SIG_DFL);
00267 pqsignal(SIGTTOU, SIG_DFL);
00268 pqsignal(SIGCONT, SIG_DFL);
00269 pqsignal(SIGWINCH, SIG_DFL);
00270 PG_SETMASK(&UnBlockSig);
00271
00272
00273
00274
00275 init_ps_display("archiver process", "", "", "");
00276
00277 pgarch_MainLoop();
00278
00279 exit(0);
00280 }
00281
00282
00283 static void
00284 pgarch_exit(SIGNAL_ARGS)
00285 {
00286
00287 exit(1);
00288 }
00289
00290
00291 static void
00292 ArchSigHupHandler(SIGNAL_ARGS)
00293 {
00294 int save_errno = errno;
00295
00296
00297 got_SIGHUP = true;
00298 SetLatch(&mainloop_latch);
00299
00300 errno = save_errno;
00301 }
00302
00303
00304 static void
00305 ArchSigTermHandler(SIGNAL_ARGS)
00306 {
00307 int save_errno = errno;
00308
00309
00310
00311
00312
00313
00314
00315 got_SIGTERM = true;
00316 SetLatch(&mainloop_latch);
00317
00318 errno = save_errno;
00319 }
00320
00321
00322 static void
00323 pgarch_waken(SIGNAL_ARGS)
00324 {
00325 int save_errno = errno;
00326
00327
00328 wakened = true;
00329 SetLatch(&mainloop_latch);
00330
00331 errno = save_errno;
00332 }
00333
00334
00335 static void
00336 pgarch_waken_stop(SIGNAL_ARGS)
00337 {
00338 int save_errno = errno;
00339
00340
00341 ready_to_stop = true;
00342 SetLatch(&mainloop_latch);
00343
00344 errno = save_errno;
00345 }
00346
00347
00348
00349
00350
00351
00352 static void
00353 pgarch_MainLoop(void)
00354 {
00355 pg_time_t last_copy_time = 0;
00356 bool time_to_stop;
00357
00358
00359
00360
00361
00362
00363
00364 wakened = true;
00365
00366
00367
00368
00369
00370
00371 do
00372 {
00373 ResetLatch(&mainloop_latch);
00374
00375
00376 time_to_stop = ready_to_stop;
00377
00378
00379 if (got_SIGHUP)
00380 {
00381 got_SIGHUP = false;
00382 ProcessConfigFile(PGC_SIGHUP);
00383 }
00384
00385
00386
00387
00388
00389
00390
00391
00392 if (got_SIGTERM)
00393 {
00394 time_t curtime = time(NULL);
00395
00396 if (last_sigterm_time == 0)
00397 last_sigterm_time = curtime;
00398 else if ((unsigned int) (curtime - last_sigterm_time) >=
00399 (unsigned int) 60)
00400 break;
00401 }
00402
00403
00404 if (wakened || time_to_stop)
00405 {
00406 wakened = false;
00407 pgarch_ArchiverCopyLoop();
00408 last_copy_time = time(NULL);
00409 }
00410
00411
00412
00413
00414
00415
00416 if (!time_to_stop)
00417 {
00418 pg_time_t curtime = (pg_time_t) time(NULL);
00419 int timeout;
00420
00421 timeout = PGARCH_AUTOWAKE_INTERVAL - (curtime - last_copy_time);
00422 if (timeout > 0)
00423 {
00424 int rc;
00425
00426 rc = WaitLatch(&mainloop_latch,
00427 WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
00428 timeout * 1000L);
00429 if (rc & WL_TIMEOUT)
00430 wakened = true;
00431 }
00432 else
00433 wakened = true;
00434 }
00435
00436
00437
00438
00439
00440
00441 } while (PostmasterIsAlive() && !time_to_stop);
00442 }
00443
00444
00445
00446
00447
00448
00449 static void
00450 pgarch_ArchiverCopyLoop(void)
00451 {
00452 char xlog[MAX_XFN_CHARS + 1];
00453
00454
00455
00456
00457
00458
00459
00460 while (pgarch_readyXlog(xlog))
00461 {
00462 int failures = 0;
00463
00464 for (;;)
00465 {
00466
00467
00468
00469
00470
00471
00472
00473 if (got_SIGTERM || !PostmasterIsAlive())
00474 return;
00475
00476
00477
00478
00479
00480
00481 if (got_SIGHUP)
00482 {
00483 got_SIGHUP = false;
00484 ProcessConfigFile(PGC_SIGHUP);
00485 }
00486
00487
00488 if (!XLogArchiveCommandSet())
00489 {
00490 ereport(WARNING,
00491 (errmsg("archive_mode enabled, yet archive_command is not set")));
00492 return;
00493 }
00494
00495 if (pgarch_archiveXlog(xlog))
00496 {
00497
00498 pgarch_archiveDone(xlog);
00499 break;
00500 }
00501 else
00502 {
00503 if (++failures >= NUM_ARCHIVE_RETRIES)
00504 {
00505 ereport(WARNING,
00506 (errmsg("archiving transaction log file \"%s\" failed too many times, will try again later",
00507 xlog)));
00508 return;
00509 }
00510 pg_usleep(1000000L);
00511 }
00512 }
00513 }
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523 static bool
00524 pgarch_archiveXlog(char *xlog)
00525 {
00526 char xlogarchcmd[MAXPGPATH];
00527 char pathname[MAXPGPATH];
00528 char activitymsg[MAXFNAMELEN + 16];
00529 char *dp;
00530 char *endp;
00531 const char *sp;
00532 int rc;
00533
00534 snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog);
00535
00536
00537
00538
00539 dp = xlogarchcmd;
00540 endp = xlogarchcmd + MAXPGPATH - 1;
00541 *endp = '\0';
00542
00543 for (sp = XLogArchiveCommand; *sp; sp++)
00544 {
00545 if (*sp == '%')
00546 {
00547 switch (sp[1])
00548 {
00549 case 'p':
00550
00551 sp++;
00552 strlcpy(dp, pathname, endp - dp);
00553 make_native_path(dp);
00554 dp += strlen(dp);
00555 break;
00556 case 'f':
00557
00558 sp++;
00559 strlcpy(dp, xlog, endp - dp);
00560 dp += strlen(dp);
00561 break;
00562 case '%':
00563
00564 sp++;
00565 if (dp < endp)
00566 *dp++ = *sp;
00567 break;
00568 default:
00569
00570 if (dp < endp)
00571 *dp++ = *sp;
00572 break;
00573 }
00574 }
00575 else
00576 {
00577 if (dp < endp)
00578 *dp++ = *sp;
00579 }
00580 }
00581 *dp = '\0';
00582
00583 ereport(DEBUG3,
00584 (errmsg_internal("executing archive command \"%s\"",
00585 xlogarchcmd)));
00586
00587
00588 snprintf(activitymsg, sizeof(activitymsg), "archiving %s", xlog);
00589 set_ps_display(activitymsg, false);
00590
00591 rc = system(xlogarchcmd);
00592 if (rc != 0)
00593 {
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 int lev = (WIFSIGNALED(rc) || WEXITSTATUS(rc) > 128) ? FATAL : LOG;
00605
00606 if (WIFEXITED(rc))
00607 {
00608 ereport(lev,
00609 (errmsg("archive command failed with exit code %d",
00610 WEXITSTATUS(rc)),
00611 errdetail("The failed archive command was: %s",
00612 xlogarchcmd)));
00613 }
00614 else if (WIFSIGNALED(rc))
00615 {
00616 #if defined(WIN32)
00617 ereport(lev,
00618 (errmsg("archive command was terminated by exception 0x%X",
00619 WTERMSIG(rc)),
00620 errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
00621 errdetail("The failed archive command was: %s",
00622 xlogarchcmd)));
00623 #elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
00624 ereport(lev,
00625 (errmsg("archive command was terminated by signal %d: %s",
00626 WTERMSIG(rc),
00627 WTERMSIG(rc) < NSIG ? sys_siglist[WTERMSIG(rc)] : "(unknown)"),
00628 errdetail("The failed archive command was: %s",
00629 xlogarchcmd)));
00630 #else
00631 ereport(lev,
00632 (errmsg("archive command was terminated by signal %d",
00633 WTERMSIG(rc)),
00634 errdetail("The failed archive command was: %s",
00635 xlogarchcmd)));
00636 #endif
00637 }
00638 else
00639 {
00640 ereport(lev,
00641 (errmsg("archive command exited with unrecognized status %d",
00642 rc),
00643 errdetail("The failed archive command was: %s",
00644 xlogarchcmd)));
00645 }
00646
00647 snprintf(activitymsg, sizeof(activitymsg), "failed on %s", xlog);
00648 set_ps_display(activitymsg, false);
00649
00650 return false;
00651 }
00652 ereport(DEBUG1,
00653 (errmsg("archived transaction log file \"%s\"", xlog)));
00654
00655 snprintf(activitymsg, sizeof(activitymsg), "last was %s", xlog);
00656 set_ps_display(activitymsg, false);
00657
00658 return true;
00659 }
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682 static bool
00683 pgarch_readyXlog(char *xlog)
00684 {
00685
00686
00687
00688
00689
00690
00691 char XLogArchiveStatusDir[MAXPGPATH];
00692 char newxlog[MAX_XFN_CHARS + 6 + 1];
00693 DIR *rldir;
00694 struct dirent *rlde;
00695 bool found = false;
00696
00697 snprintf(XLogArchiveStatusDir, MAXPGPATH, XLOGDIR "/archive_status");
00698 rldir = AllocateDir(XLogArchiveStatusDir);
00699 if (rldir == NULL)
00700 ereport(ERROR,
00701 (errcode_for_file_access(),
00702 errmsg("could not open archive status directory \"%s\": %m",
00703 XLogArchiveStatusDir)));
00704
00705 while ((rlde = ReadDir(rldir, XLogArchiveStatusDir)) != NULL)
00706 {
00707 int basenamelen = (int) strlen(rlde->d_name) - 6;
00708
00709 if (basenamelen >= MIN_XFN_CHARS &&
00710 basenamelen <= MAX_XFN_CHARS &&
00711 strspn(rlde->d_name, VALID_XFN_CHARS) >= basenamelen &&
00712 strcmp(rlde->d_name + basenamelen, ".ready") == 0)
00713 {
00714 if (!found)
00715 {
00716 strcpy(newxlog, rlde->d_name);
00717 found = true;
00718 }
00719 else
00720 {
00721 if (strcmp(rlde->d_name, newxlog) < 0)
00722 strcpy(newxlog, rlde->d_name);
00723 }
00724 }
00725 }
00726 FreeDir(rldir);
00727
00728 if (found)
00729 {
00730
00731 newxlog[strlen(newxlog) - 6] = '\0';
00732 strcpy(xlog, newxlog);
00733 }
00734 return found;
00735 }
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745 static void
00746 pgarch_archiveDone(char *xlog)
00747 {
00748 char rlogready[MAXPGPATH];
00749 char rlogdone[MAXPGPATH];
00750
00751 StatusFilePath(rlogready, xlog, ".ready");
00752 StatusFilePath(rlogdone, xlog, ".done");
00753 if (rename(rlogready, rlogdone) < 0)
00754 ereport(WARNING,
00755 (errcode_for_file_access(),
00756 errmsg("could not rename file \"%s\" to \"%s\": %m",
00757 rlogready, rlogdone)));
00758 }