1 /*------------------------------------------------------------------------- 2 * 3 * pgarch.c 4 * 5 * PostgreSQL WAL archiver 6 * 7 * All functions relating to archiver are included here 8 * 9 * - All functions executed by archiver process 10 * 11 * - archiver is forked from postmaster, and the two 12 * processes then communicate using signals. All functions 13 * executed by postmaster are included in this file. 14 * 15 * Initial author: Simon Riggs simon@2ndquadrant.com 16 * 17 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group 18 * Portions Copyright (c) 1994, Regents of the University of California 19 * 20 * 21 * IDENTIFICATION 22 * src/backend/postmaster/pgarch.c 23 * 24 *------------------------------------------------------------------------- 25 */ 26 #include "postgres.h" 27 28 #include <fcntl.h> 29 #include <signal.h> 30 #include <time.h> 31 #include <sys/stat.h> 32 #include <sys/time.h> 33 #include <sys/wait.h> 34 #include <unistd.h> 35 36 #include "access/xlog.h" 37 #include "access/xlog_internal.h" 38 #include "libpq/pqsignal.h" 39 #include "miscadmin.h" 40 #include "pgstat.h" 41 #include "postmaster/fork_process.h" 42 #include "postmaster/pgarch.h" 43 #include "postmaster/postmaster.h" 44 #include "storage/dsm.h" 45 #include "storage/fd.h" 46 #include "storage/ipc.h" 47 #include "storage/latch.h" 48 #include "storage/pg_shmem.h" 49 #include "storage/pmsignal.h" 50 #include "utils/guc.h" 51 #include "utils/ps_status.h" 52 53 54 /* ---------- 55 * Timer definitions. 56 * ---------- 57 */ 58 #define PGARCH_AUTOWAKE_INTERVAL 60 /* How often to force a poll of the 59 * archive status directory; in seconds. */ 60 #define PGARCH_RESTART_INTERVAL 10 /* How often to attempt to restart a 61 * failed archiver; in seconds. */ 62 63 /* 64 * Maximum number of retries allowed when attempting to archive a WAL 65 * file. 66 */ 67 #define NUM_ARCHIVE_RETRIES 3 68 69 /* 70 * Maximum number of retries allowed when attempting to remove an 71 * orphan archive status file. 72 */ 73 #define NUM_ORPHAN_CLEANUP_RETRIES 3 74 75 76 /* ---------- 77 * Local data 78 * ---------- 79 */ 80 static time_t last_pgarch_start_time; 81 static time_t last_sigterm_time = 0; 82 83 /* 84 * Flags set by interrupt handlers for later service in the main loop. 85 */ 86 static volatile sig_atomic_t got_SIGHUP = false; 87 static volatile sig_atomic_t got_SIGTERM = false; 88 static volatile sig_atomic_t wakened = false; 89 static volatile sig_atomic_t ready_to_stop = false; 90 91 /* ---------- 92 * Local function forward declarations 93 * ---------- 94 */ 95 #ifdef EXEC_BACKEND 96 static pid_t pgarch_forkexec(void); 97 #endif 98 99 NON_EXEC_STATIC void PgArchiverMain(int argc, char *argv[]) pg_attribute_noreturn(); 100 static void pgarch_exit(SIGNAL_ARGS); 101 static void ArchSigHupHandler(SIGNAL_ARGS); 102 static void ArchSigTermHandler(SIGNAL_ARGS); 103 static void pgarch_waken(SIGNAL_ARGS); 104 static void pgarch_waken_stop(SIGNAL_ARGS); 105 static void pgarch_MainLoop(void); 106 static void pgarch_ArchiverCopyLoop(void); 107 static bool pgarch_archiveXlog(char *xlog); 108 static bool pgarch_readyXlog(char *xlog); 109 static void pgarch_archiveDone(char *xlog); 110 111 112 /* ------------------------------------------------------------ 113 * Public functions called from postmaster follow 114 * ------------------------------------------------------------ 115 */ 116 117 /* 118 * pgarch_start 119 * 120 * Called from postmaster at startup or after an existing archiver 121 * died. Attempt to fire up a fresh archiver process. 122 * 123 * Returns PID of child process, or 0 if fail. 124 * 125 * Note: if fail, we will be called again from the postmaster main loop. 126 */ 127 int 128 pgarch_start(void) 129 { 130 time_t curtime; 131 pid_t pgArchPid; 132 133 /* 134 * Do nothing if no archiver needed 135 */ 136 if (!XLogArchivingActive()) 137 return 0; 138 139 /* 140 * Do nothing if too soon since last archiver start. This is a safety 141 * valve to protect against continuous respawn attempts if the archiver is 142 * dying immediately at launch. Note that since we will be re-called from 143 * the postmaster main loop, we will get another chance later. 144 */ 145 curtime = time(NULL); 146 if ((unsigned int) (curtime - last_pgarch_start_time) < 147 (unsigned int) PGARCH_RESTART_INTERVAL) 148 return 0; 149 last_pgarch_start_time = curtime; 150 151 #ifdef EXEC_BACKEND 152 switch ((pgArchPid = pgarch_forkexec())) 153 #else 154 switch ((pgArchPid = fork_process())) 155 #endif 156 { 157 case -1: 158 ereport(LOG, 159 (errmsg("could not fork archiver: %m"))); 160 return 0; 161 162 #ifndef EXEC_BACKEND 163 case 0: 164 /* in postmaster child ... */ 165 InitPostmasterChild(); 166 167 /* Close the postmaster's sockets */ 168 ClosePostmasterPorts(false); 169 170 /* Drop our connection to postmaster's shared memory, as well */ 171 dsm_detach_all(); 172 PGSharedMemoryDetach(); 173 174 PgArchiverMain(0, NULL); 175 break; 176 #endif 177 178 default: 179 return (int) pgArchPid; 180 } 181 182 /* shouldn't get here */ 183 return 0; 184 } 185 186 /* ------------------------------------------------------------ 187 * Local functions called by archiver follow 188 * ------------------------------------------------------------ 189 */ 190 191 192 #ifdef EXEC_BACKEND CheckpointerMain(void)193 194 /* 195 * pgarch_forkexec() - 196 * 197 * Format up the arglist for, then fork and exec, archive process 198 */ 199 static pid_t 200 pgarch_forkexec(void) 201 { 202 char *av[10]; 203 int ac = 0; 204 205 av[ac++] = "postgres"; 206 207 av[ac++] = "--forkarch"; 208 209 av[ac++] = NULL; /* filled in by postmaster_forkexec */ 210 211 av[ac] = NULL; 212 Assert(ac < lengthof(av)); 213 214 return postmaster_forkexec(ac, av); 215 } 216 #endif /* EXEC_BACKEND */ 217 218 219 /* 220 * PgArchiverMain 221 * 222 * The argc/argv parameters are valid only in EXEC_BACKEND case. However, 223 * since we don't use 'em, it hardly matters... 224 */ 225 NON_EXEC_STATIC void 226 PgArchiverMain(int argc, char *argv[]) 227 { 228 /* 229 * Ignore all signals usually bound to some action in the postmaster, 230 * except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT. 231 */ 232 pqsignal(SIGHUP, ArchSigHupHandler); 233 pqsignal(SIGINT, SIG_IGN); 234 pqsignal(SIGTERM, ArchSigTermHandler); 235 pqsignal(SIGQUIT, pgarch_exit); 236 pqsignal(SIGALRM, SIG_IGN); 237 pqsignal(SIGPIPE, SIG_IGN); 238 pqsignal(SIGUSR1, pgarch_waken); 239 pqsignal(SIGUSR2, pgarch_waken_stop); 240 /* Reset some signals that are accepted by postmaster but not here */ 241 pqsignal(SIGCHLD, SIG_DFL); 242 PG_SETMASK(&UnBlockSig); 243 244 /* 245 * Identify myself via ps 246 */ 247 init_ps_display("archiver", "", "", ""); 248 249 pgarch_MainLoop(); 250 251 exit(0); 252 } 253 254 /* SIGQUIT signal handler for archiver process */ 255 static void 256 pgarch_exit(SIGNAL_ARGS) 257 { 258 /* 259 * We DO NOT want to run proc_exit() or atexit() callbacks; they wouldn't 260 * be safe to run from a signal handler. Just nail the windows shut and 261 * get out of town. 262 * 263 * For consistency with other postmaster children, we do _exit(2) not 264 * _exit(1). The postmaster currently will treat these exit codes alike, 265 * but it seems better to report that we died in an unexpected way. 266 */ 267 _exit(2); 268 } 269 270 /* SIGHUP signal handler for archiver process */ 271 static void 272 ArchSigHupHandler(SIGNAL_ARGS) 273 { 274 int save_errno = errno; 275 276 /* set flag to re-read config file at next convenient time */ 277 got_SIGHUP = true; 278 SetLatch(MyLatch); 279 280 errno = save_errno; 281 } 282 283 /* SIGTERM signal handler for archiver process */ 284 static void 285 ArchSigTermHandler(SIGNAL_ARGS) 286 { 287 int save_errno = errno; 288 289 /* 290 * The postmaster never sends us SIGTERM, so we assume that this means 291 * that init is trying to shut down the whole system. If we hang around 292 * too long we'll get SIGKILL'd. Set flag to prevent starting any more 293 * archive commands. 294 */ 295 got_SIGTERM = true; 296 SetLatch(MyLatch); 297 298 errno = save_errno; 299 } 300 301 /* SIGUSR1 signal handler for archiver process */ 302 static void 303 pgarch_waken(SIGNAL_ARGS) 304 { 305 int save_errno = errno; 306 307 /* set flag that there is work to be done */ 308 wakened = true; 309 SetLatch(MyLatch); 310 311 errno = save_errno; 312 } 313 314 /* SIGUSR2 signal handler for archiver process */ 315 static void 316 pgarch_waken_stop(SIGNAL_ARGS) 317 { 318 int save_errno = errno; 319 320 /* set flag to do a final cycle and shut down afterwards */ 321 ready_to_stop = true; 322 SetLatch(MyLatch); 323 324 errno = save_errno; 325 } 326 327 /* 328 * pgarch_MainLoop 329 * 330 * Main loop for archiver 331 */ 332 static void 333 pgarch_MainLoop(void) 334 { 335 pg_time_t last_copy_time = 0; 336 bool time_to_stop; 337 338 /* 339 * We run the copy loop immediately upon entry, in case there are 340 * unarchived files left over from a previous database run (or maybe the 341 * archiver died unexpectedly). After that we wait for a signal or 342 * timeout before doing more. 343 */ 344 wakened = true; 345 346 /* 347 * There shouldn't be anything for the archiver to do except to wait for a 348 * signal ... however, the archiver exists to protect our data, so she 349 * wakes up occasionally to allow herself to be proactive. 350 */ 351 do 352 { 353 ResetLatch(MyLatch); 354 355 /* When we get SIGUSR2, we do one more archive cycle, then exit */ 356 time_to_stop = ready_to_stop; 357 358 /* Check for config update */ 359 if (got_SIGHUP) 360 { 361 got_SIGHUP = false; 362 ProcessConfigFile(PGC_SIGHUP); 363 } 364 365 /* 366 * If we've gotten SIGTERM, we normally just sit and do nothing until 367 * SIGUSR2 arrives. However, that means a random SIGTERM would 368 * disable archiving indefinitely, which doesn't seem like a good 369 * idea. If more than 60 seconds pass since SIGTERM, exit anyway, so 370 * that the postmaster can start a new archiver if needed. 371 */ 372 if (got_SIGTERM) 373 { 374 time_t curtime = time(NULL); 375 376 if (last_sigterm_time == 0) 377 last_sigterm_time = curtime; 378 else if ((unsigned int) (curtime - last_sigterm_time) >= 379 (unsigned int) 60) 380 break; 381 } 382 383 /* Do what we're here for */ 384 if (wakened || time_to_stop) 385 { 386 wakened = false; 387 pgarch_ArchiverCopyLoop(); 388 last_copy_time = time(NULL); 389 } 390 391 /* 392 * Sleep until a signal is received, or until a poll is forced by 393 * PGARCH_AUTOWAKE_INTERVAL having passed since last_copy_time, or 394 * until postmaster dies. 395 */ 396 if (!time_to_stop) /* Don't wait during last iteration */ 397 { 398 pg_time_t curtime = (pg_time_t) time(NULL); 399 int timeout; 400 401 timeout = PGARCH_AUTOWAKE_INTERVAL - (curtime - last_copy_time); 402 if (timeout > 0) 403 { 404 int rc; 405 406 rc = WaitLatch(MyLatch, 407 WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, 408 timeout * 1000L, 409 WAIT_EVENT_ARCHIVER_MAIN); 410 if (rc & WL_TIMEOUT) 411 wakened = true; 412 if (rc & WL_POSTMASTER_DEATH) 413 time_to_stop = true; 414 } 415 else 416 wakened = true; 417 } 418 419 /* 420 * The archiver quits either when the postmaster dies (not expected) 421 * or after completing one more archiving cycle after receiving 422 * SIGUSR2. 423 */ 424 } while (!time_to_stop); 425 } 426 427 /* 428 * pgarch_ArchiverCopyLoop 429 * 430 * Archives all outstanding xlogs then returns 431 */ 432 static void 433 pgarch_ArchiverCopyLoop(void) 434 { 435 char xlog[MAX_XFN_CHARS + 1]; 436 437 /* 438 * loop through all xlogs with archive_status of .ready and archive 439 * them...mostly we expect this to be a single file, though it is possible 440 * some backend will add files onto the list of those that need archiving 441 * while we are still copying earlier archives 442 */ 443 while (pgarch_readyXlog(xlog)) 444 { 445 int failures = 0; 446 int failures_orphan = 0; 447 448 for (;;) 449 { 450 struct stat stat_buf; 451 char pathname[MAXPGPATH]; 452 453 /* 454 * Do not initiate any more archive commands after receiving 455 * SIGTERM, nor after the postmaster has died unexpectedly. The 456 * first condition is to try to keep from having init SIGKILL the 457 * command, and the second is to avoid conflicts with another 458 * archiver spawned by a newer postmaster. 459 */ 460 if (got_SIGTERM || !PostmasterIsAlive()) 461 return; 462 463 /* 464 * Check for config update. This is so that we'll adopt a new 465 * setting for archive_command as soon as possible, even if there 466 * is a backlog of files to be archived. 467 */ 468 if (got_SIGHUP) 469 { 470 got_SIGHUP = false; 471 ProcessConfigFile(PGC_SIGHUP); 472 } 473 474 /* can't do anything if no command ... */ 475 if (!XLogArchiveCommandSet()) 476 { 477 ereport(WARNING, 478 (errmsg("archive_mode enabled, yet archive_command is not set"))); 479 return; 480 } 481 482 /* 483 * Since archive status files are not removed in a durable manner, 484 * a system crash could leave behind .ready files for WAL segments 485 * that have already been recycled or removed. In this case, 486 * simply remove the orphan status file and move on. unlink() is 487 * used here as even on subsequent crashes the same orphan files 488 * would get removed, so there is no need to worry about 489 * durability. 490 */ 491 snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog); 492 if (stat(pathname, &stat_buf) != 0 && errno == ENOENT) 493 { 494 char xlogready[MAXPGPATH]; 495 496 StatusFilePath(xlogready, xlog, ".ready"); 497 if (unlink(xlogready) == 0) 498 { 499 ereport(WARNING, 500 (errmsg("removed orphan archive status file \"%s\"", 501 xlogready))); 502 503 /* leave loop and move to the next status file */ 504 break; 505 } 506 507 if (++failures_orphan >= NUM_ORPHAN_CLEANUP_RETRIES) 508 { 509 ereport(WARNING, 510 (errmsg("removal of orphan archive status file \"%s\" failed too many times, will try again later", 511 xlogready))); 512 513 /* give up cleanup of orphan status files */ 514 return; 515 } 516 517 /* wait a bit before retrying */ 518 pg_usleep(1000000L); 519 continue; 520 } 521 522 if (pgarch_archiveXlog(xlog)) 523 { 524 /* successful */ 525 pgarch_archiveDone(xlog); 526 527 /* 528 * Tell the collector about the WAL file that we successfully 529 * archived 530 */ 531 pgstat_send_archiver(xlog, false); 532 533 break; /* out of inner retry loop */ 534 } 535 else 536 { 537 /* 538 * Tell the collector about the WAL file that we failed to 539 * archive 540 */ 541 pgstat_send_archiver(xlog, true); 542 543 if (++failures >= NUM_ARCHIVE_RETRIES) 544 { 545 ereport(WARNING, 546 (errmsg("archiving write-ahead log file \"%s\" failed too many times, will try again later", 547 xlog))); 548 return; /* give up archiving for now */ 549 } 550 pg_usleep(1000000L); /* wait a bit before retrying */ 551 } 552 } 553 } 554 } 555 556 /* 557 * pgarch_archiveXlog 558 * 559 * Invokes system(3) to copy one archive file to wherever it should go 560 * 561 * Returns true if successful 562 */ 563 static bool 564 pgarch_archiveXlog(char *xlog) 565 { 566 char xlogarchcmd[MAXPGPATH]; 567 char pathname[MAXPGPATH]; 568 char activitymsg[MAXFNAMELEN + 16]; 569 char *dp; 570 char *endp; 571 const char *sp; 572 int rc; 573 CheckArchiveTimeout(void)574 snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog); 575 576 /* 577 * construct the command to be executed 578 */ 579 dp = xlogarchcmd; 580 endp = xlogarchcmd + MAXPGPATH - 1; 581 *endp = '\0'; 582 583 for (sp = XLogArchiveCommand; *sp; sp++) 584 { 585 if (*sp == '%') 586 { 587 switch (sp[1]) 588 { 589 case 'p': 590 /* %p: relative path of source file */ 591 sp++; 592 strlcpy(dp, pathname, endp - dp); 593 make_native_path(dp); 594 dp += strlen(dp); 595 break; 596 case 'f': 597 /* %f: filename of source file */ 598 sp++; 599 strlcpy(dp, xlog, endp - dp); 600 dp += strlen(dp); 601 break; 602 case '%': 603 /* convert %% to a single % */ 604 sp++; 605 if (dp < endp) 606 *dp++ = *sp; 607 break; 608 default: 609 /* otherwise treat the % as not special */ 610 if (dp < endp) 611 *dp++ = *sp; 612 break; 613 } 614 } 615 else 616 { 617 if (dp < endp) 618 *dp++ = *sp; 619 } 620 } 621 *dp = '\0'; 622 623 ereport(DEBUG3, 624 (errmsg_internal("executing archive command \"%s\"", 625 xlogarchcmd))); 626 627 /* Report archive activity in PS display */ 628 snprintf(activitymsg, sizeof(activitymsg), "archiving %s", xlog); 629 set_ps_display(activitymsg, false); 630 631 rc = system(xlogarchcmd); 632 if (rc != 0) 633 { 634 /* ImmediateCheckpointRequested(void)635 * If either the shell itself, or a called command, died on a signal, 636 * abort the archiver. We do this because system() ignores SIGINT and 637 * SIGQUIT while waiting; so a signal is very likely something that 638 * should have interrupted us too. Also die if the shell got a hard 639 * "command not found" type of error. If we overreact it's no big 640 * deal, the postmaster will just start the archiver again. 641 */ 642 int lev = wait_result_is_any_signal(rc, true) ? FATAL : LOG; 643 644 if (WIFEXITED(rc)) 645 { 646 ereport(lev, 647 (errmsg("archive command failed with exit code %d", 648 WEXITSTATUS(rc)), 649 errdetail("The failed archive command was: %s", 650 xlogarchcmd))); 651 } 652 else if (WIFSIGNALED(rc)) 653 { 654 #if defined(WIN32) 655 ereport(lev, 656 (errmsg("archive command was terminated by exception 0x%X", 657 WTERMSIG(rc)), 658 errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."), 659 errdetail("The failed archive command was: %s", 660 xlogarchcmd))); 661 #else CheckpointWriteDelay(int flags,double progress)662 ereport(lev, 663 (errmsg("archive command was terminated by signal %d: %s", 664 WTERMSIG(rc), pg_strsignal(WTERMSIG(rc))), 665 errdetail("The failed archive command was: %s", 666 xlogarchcmd))); 667 #endif 668 } 669 else 670 { 671 ereport(lev, 672 (errmsg("archive command exited with unrecognized status %d", 673 rc), 674 errdetail("The failed archive command was: %s", 675 xlogarchcmd))); 676 } 677 678 snprintf(activitymsg, sizeof(activitymsg), "failed on %s", xlog); 679 set_ps_display(activitymsg, false); 680 681 return false; 682 } 683 elog(DEBUG1, "archived write-ahead log file \"%s\"", xlog); 684 685 snprintf(activitymsg, sizeof(activitymsg), "last was %s", xlog); 686 set_ps_display(activitymsg, false); 687 688 return true; 689 } 690 691 /* 692 * pgarch_readyXlog 693 * 694 * Return name of the oldest xlog file that has not yet been archived. 695 * No notification is set that file archiving is now in progress, so 696 * this would need to be extended if multiple concurrent archival 697 * tasks were created. If a failure occurs, we will completely 698 * re-copy the file at the next available opportunity. 699 * 700 * It is important that we return the oldest, so that we archive xlogs 701 * in order that they were written, for two reasons: 702 * 1) to maintain the sequential chain of xlogs required for recovery 703 * 2) because the oldest ones will sooner become candidates for 704 * recycling at time of checkpoint 705 * 706 * NOTE: the "oldest" comparison will consider any .history file to be older 707 * than any other file except another .history file. Segments on a timeline 708 * with a smaller ID will be older than all segments on a timeline with a 709 * larger ID; the net result being that past timelines are given higher 710 * priority for archiving. This seems okay, or at least not obviously worth 711 * changing. 712 */ 713 static bool 714 pgarch_readyXlog(char *xlog) 715 { 716 /* 717 * open xlog status directory and read through list of xlogs that have the 718 * .ready suffix, looking for earliest file. It is possible to optimise 719 * this code, though only a single file is expected on the vast majority 720 * of calls, so.... 721 */ 722 char XLogArchiveStatusDir[MAXPGPATH]; 723 DIR *rldir; 724 struct dirent *rlde; 725 bool found = false; IsCheckpointOnSchedule(double progress)726 bool historyFound = false; 727 728 snprintf(XLogArchiveStatusDir, MAXPGPATH, XLOGDIR "/archive_status"); 729 rldir = AllocateDir(XLogArchiveStatusDir); 730 731 while ((rlde = ReadDir(rldir, XLogArchiveStatusDir)) != NULL) 732 { 733 int basenamelen = (int) strlen(rlde->d_name) - 6; 734 char basename[MAX_XFN_CHARS + 1]; 735 bool ishistory; 736 737 /* Ignore entries with unexpected number of characters */ 738 if (basenamelen < MIN_XFN_CHARS || 739 basenamelen > MAX_XFN_CHARS) 740 continue; 741 742 /* Ignore entries with unexpected characters */ 743 if (strspn(rlde->d_name, VALID_XFN_CHARS) < basenamelen) 744 continue; 745 746 /* Ignore anything not suffixed with .ready */ 747 if (strcmp(rlde->d_name + basenamelen, ".ready") != 0) 748 continue; 749 750 /* Truncate off the .ready */ 751 memcpy(basename, rlde->d_name, basenamelen); 752 basename[basenamelen] = '\0'; 753 754 /* Is this a history file? */ 755 ishistory = IsTLHistoryFileName(basename); 756 757 /* 758 * Consume the file to archive. History files have the highest 759 * priority. If this is the first file or the first history file 760 * ever, copy it. In the presence of a history file already chosen as 761 * target, ignore all other files except history files which have been 762 * generated for an older timeline than what is already chosen as 763 * target to archive. 764 */ 765 if (!found || (ishistory && !historyFound)) 766 { 767 strcpy(xlog, basename); 768 found = true; 769 historyFound = ishistory; 770 } 771 else if (ishistory || !historyFound) 772 { 773 if (strcmp(basename, xlog) < 0) 774 strcpy(xlog, basename); 775 } 776 } 777 FreeDir(rldir); 778 779 return found; 780 } 781 782 /* 783 * pgarch_archiveDone 784 * 785 * Emit notification that an xlog file has been successfully archived. 786 * We do this by renaming the status file from NNN.ready to NNN.done. 787 * Eventually, a checkpoint process will notice this and delete both the 788 * NNN.done file and the xlog file itself. 789 */ 790 static void 791 pgarch_archiveDone(char *xlog) 792 { 793 char rlogready[MAXPGPATH]; 794 char rlogdone[MAXPGPATH]; 795 796 StatusFilePath(rlogready, xlog, ".ready"); 797 StatusFilePath(rlogdone, xlog, ".done"); 798 (void) durable_rename(rlogready, rlogdone, WARNING); 799 } 800