Line data Source code
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-2023, 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 <time.h>
29 : #include <sys/stat.h>
30 : #include <unistd.h>
31 :
32 : #include "access/xlog.h"
33 : #include "access/xlog_internal.h"
34 : #include "archive/archive_module.h"
35 : #include "archive/shell_archive.h"
36 : #include "lib/binaryheap.h"
37 : #include "libpq/pqsignal.h"
38 : #include "pgstat.h"
39 : #include "postmaster/interrupt.h"
40 : #include "postmaster/pgarch.h"
41 : #include "storage/fd.h"
42 : #include "storage/ipc.h"
43 : #include "storage/latch.h"
44 : #include "storage/pmsignal.h"
45 : #include "storage/proc.h"
46 : #include "storage/procsignal.h"
47 : #include "storage/shmem.h"
48 : #include "storage/spin.h"
49 : #include "utils/guc.h"
50 : #include "utils/memutils.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 : * Maximum number of .ready files to gather per directory scan.
77 : */
78 : #define NUM_FILES_PER_DIRECTORY_SCAN 64
79 :
80 : /* Shared memory area for archiver process */
81 : typedef struct PgArchData
82 : {
83 : int pgprocno; /* pgprocno of archiver process */
84 :
85 : /*
86 : * Forces a directory scan in pgarch_readyXlog(). Protected by arch_lck.
87 : */
88 : bool force_dir_scan;
89 :
90 : slock_t arch_lck;
91 : } PgArchData;
92 :
93 : char *XLogArchiveLibrary = "";
94 :
95 :
96 : /* ----------
97 : * Local data
98 : * ----------
99 : */
100 : static time_t last_sigterm_time = 0;
101 : static PgArchData *PgArch = NULL;
102 : static const ArchiveModuleCallbacks *ArchiveCallbacks;
103 : static ArchiveModuleState *archive_module_state;
104 :
105 :
106 : /*
107 : * Stuff for tracking multiple files to archive from each scan of
108 : * archive_status. Minimizing the number of directory scans when there are
109 : * many files to archive can significantly improve archival rate.
110 : *
111 : * arch_heap is a max-heap that is used during the directory scan to track
112 : * the highest-priority files to archive. After the directory scan
113 : * completes, the file names are stored in ascending order of priority in
114 : * arch_files. pgarch_readyXlog() returns files from arch_files until it
115 : * is empty, at which point another directory scan must be performed.
116 : *
117 : * We only need this data in the archiver process, so make it a palloc'd
118 : * struct rather than a bunch of static arrays.
119 : */
120 : struct arch_files_state
121 : {
122 : binaryheap *arch_heap;
123 : int arch_files_size; /* number of live entries in arch_files[] */
124 : char *arch_files[NUM_FILES_PER_DIRECTORY_SCAN];
125 : /* buffers underlying heap, and later arch_files[], entries: */
126 : char arch_filenames[NUM_FILES_PER_DIRECTORY_SCAN][MAX_XFN_CHARS + 1];
127 : };
128 :
129 : static struct arch_files_state *arch_files = NULL;
130 :
131 : /*
132 : * Flags set by interrupt handlers for later service in the main loop.
133 : */
134 : static volatile sig_atomic_t ready_to_stop = false;
135 :
136 : /* ----------
137 : * Local function forward declarations
138 : * ----------
139 : */
140 : static void pgarch_waken_stop(SIGNAL_ARGS);
141 : static void pgarch_MainLoop(void);
142 : static void pgarch_ArchiverCopyLoop(void);
143 : static bool pgarch_archiveXlog(char *xlog);
144 : static bool pgarch_readyXlog(char *xlog);
145 : static void pgarch_archiveDone(char *xlog);
146 : static void pgarch_die(int code, Datum arg);
147 : static void HandlePgArchInterrupts(void);
148 : static int ready_file_comparator(Datum a, Datum b, void *arg);
149 : static void LoadArchiveLibrary(void);
150 : static void pgarch_call_module_shutdown_cb(int code, Datum arg);
151 :
152 : /* Report shared memory space needed by PgArchShmemInit */
153 : Size
154 6058 : PgArchShmemSize(void)
155 : {
156 6058 : Size size = 0;
157 :
158 6058 : size = add_size(size, sizeof(PgArchData));
159 :
160 6058 : return size;
161 : }
162 :
163 : /* Allocate and initialize archiver-related shared memory */
164 : void
165 1562 : PgArchShmemInit(void)
166 : {
167 : bool found;
168 :
169 1562 : PgArch = (PgArchData *)
170 1562 : ShmemInitStruct("Archiver Data", PgArchShmemSize(), &found);
171 :
172 1562 : if (!found)
173 : {
174 : /* First time through, so initialize */
175 3124 : MemSet(PgArch, 0, PgArchShmemSize());
176 1562 : PgArch->pgprocno = INVALID_PGPROCNO;
177 1562 : SpinLockInit(&PgArch->arch_lck);
178 : }
179 1562 : }
180 :
181 : /*
182 : * PgArchCanRestart
183 : *
184 : * Return true and archiver is allowed to restart if enough time has
185 : * passed since it was launched last to reach PGARCH_RESTART_INTERVAL.
186 : * Otherwise return false.
187 : *
188 : * This is a safety valve to protect against continuous respawn attempts if the
189 : * archiver is dying immediately at launch. Note that since we will retry to
190 : * launch the archiver from the postmaster main loop, we will get another
191 : * chance later.
192 : */
193 : bool
194 62 : PgArchCanRestart(void)
195 : {
196 : static time_t last_pgarch_start_time = 0;
197 62 : time_t curtime = time(NULL);
198 :
199 : /*
200 : * Return false and don't restart archiver if too soon since last archiver
201 : * start.
202 : */
203 62 : if ((unsigned int) (curtime - last_pgarch_start_time) <
204 : (unsigned int) PGARCH_RESTART_INTERVAL)
205 0 : return false;
206 :
207 62 : last_pgarch_start_time = curtime;
208 62 : return true;
209 : }
210 :
211 :
212 : /* Main entry point for archiver process */
213 : void
214 24 : PgArchiverMain(void)
215 : {
216 : /*
217 : * Ignore all signals usually bound to some action in the postmaster,
218 : * except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT.
219 : */
220 24 : pqsignal(SIGHUP, SignalHandlerForConfigReload);
221 24 : pqsignal(SIGINT, SIG_IGN);
222 24 : pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
223 : /* SIGQUIT handler was already set up by InitPostmasterChild */
224 24 : pqsignal(SIGALRM, SIG_IGN);
225 24 : pqsignal(SIGPIPE, SIG_IGN);
226 24 : pqsignal(SIGUSR1, procsignal_sigusr1_handler);
227 24 : pqsignal(SIGUSR2, pgarch_waken_stop);
228 :
229 : /* Reset some signals that are accepted by postmaster but not here */
230 24 : pqsignal(SIGCHLD, SIG_DFL);
231 :
232 : /* Unblock signals (they were blocked when the postmaster forked us) */
233 24 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
234 :
235 : /* We shouldn't be launched unnecessarily. */
236 : Assert(XLogArchivingActive());
237 :
238 : /* Arrange to clean up at archiver exit */
239 24 : on_shmem_exit(pgarch_die, 0);
240 :
241 : /*
242 : * Advertise our pgprocno so that backends can use our latch to wake us up
243 : * while we're sleeping.
244 : */
245 24 : PgArch->pgprocno = MyProc->pgprocno;
246 :
247 : /* Create workspace for pgarch_readyXlog() */
248 24 : arch_files = palloc(sizeof(struct arch_files_state));
249 24 : arch_files->arch_files_size = 0;
250 :
251 : /* Initialize our max-heap for prioritizing files to archive. */
252 24 : arch_files->arch_heap = binaryheap_allocate(NUM_FILES_PER_DIRECTORY_SCAN,
253 : ready_file_comparator, NULL);
254 :
255 : /* Load the archive_library. */
256 24 : LoadArchiveLibrary();
257 :
258 24 : pgarch_MainLoop();
259 :
260 24 : proc_exit(0);
261 : }
262 :
263 : /*
264 : * Wake up the archiver
265 : */
266 : void
267 132 : PgArchWakeup(void)
268 : {
269 132 : int arch_pgprocno = PgArch->pgprocno;
270 :
271 : /*
272 : * We don't acquire ProcArrayLock here. It's actually fine because
273 : * procLatch isn't ever freed, so we just can potentially set the wrong
274 : * process' (or no process') latch. Even in that case the archiver will
275 : * be relaunched shortly and will start archiving.
276 : */
277 132 : if (arch_pgprocno != INVALID_PGPROCNO)
278 104 : SetLatch(&ProcGlobal->allProcs[arch_pgprocno].procLatch);
279 132 : }
280 :
281 :
282 : /* SIGUSR2 signal handler for archiver process */
283 : static void
284 24 : pgarch_waken_stop(SIGNAL_ARGS)
285 : {
286 24 : int save_errno = errno;
287 :
288 : /* set flag to do a final cycle and shut down afterwards */
289 24 : ready_to_stop = true;
290 24 : SetLatch(MyLatch);
291 :
292 24 : errno = save_errno;
293 24 : }
294 :
295 : /*
296 : * pgarch_MainLoop
297 : *
298 : * Main loop for archiver
299 : */
300 : static void
301 106 : pgarch_MainLoop(void)
302 : {
303 : bool time_to_stop;
304 :
305 : /*
306 : * There shouldn't be anything for the archiver to do except to wait for a
307 : * signal ... however, the archiver exists to protect our data, so it
308 : * wakes up occasionally to allow itself to be proactive.
309 : */
310 : do
311 : {
312 106 : ResetLatch(MyLatch);
313 :
314 : /* When we get SIGUSR2, we do one more archive cycle, then exit */
315 106 : time_to_stop = ready_to_stop;
316 :
317 : /* Check for barrier events and config update */
318 106 : HandlePgArchInterrupts();
319 :
320 : /*
321 : * If we've gotten SIGTERM, we normally just sit and do nothing until
322 : * SIGUSR2 arrives. However, that means a random SIGTERM would
323 : * disable archiving indefinitely, which doesn't seem like a good
324 : * idea. If more than 60 seconds pass since SIGTERM, exit anyway, so
325 : * that the postmaster can start a new archiver if needed.
326 : */
327 106 : if (ShutdownRequestPending)
328 : {
329 0 : time_t curtime = time(NULL);
330 :
331 0 : if (last_sigterm_time == 0)
332 0 : last_sigterm_time = curtime;
333 0 : else if ((unsigned int) (curtime - last_sigterm_time) >=
334 : (unsigned int) 60)
335 0 : break;
336 : }
337 :
338 : /* Do what we're here for */
339 106 : pgarch_ArchiverCopyLoop();
340 :
341 : /*
342 : * Sleep until a signal is received, or until a poll is forced by
343 : * PGARCH_AUTOWAKE_INTERVAL, or until postmaster dies.
344 : */
345 106 : if (!time_to_stop) /* Don't wait during last iteration */
346 : {
347 : int rc;
348 :
349 82 : rc = WaitLatch(MyLatch,
350 : WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
351 : PGARCH_AUTOWAKE_INTERVAL * 1000L,
352 : WAIT_EVENT_ARCHIVER_MAIN);
353 82 : if (rc & WL_POSTMASTER_DEATH)
354 0 : time_to_stop = true;
355 : }
356 :
357 : /*
358 : * The archiver quits either when the postmaster dies (not expected)
359 : * or after completing one more archiving cycle after receiving
360 : * SIGUSR2.
361 : */
362 106 : } while (!time_to_stop);
363 24 : }
364 :
365 : /*
366 : * pgarch_ArchiverCopyLoop
367 : *
368 : * Archives all outstanding xlogs then returns
369 : */
370 : static void
371 106 : pgarch_ArchiverCopyLoop(void)
372 : {
373 : char xlog[MAX_XFN_CHARS + 1];
374 :
375 : /* force directory scan in the first call to pgarch_readyXlog() */
376 106 : arch_files->arch_files_size = 0;
377 :
378 : /*
379 : * loop through all xlogs with archive_status of .ready and archive
380 : * them...mostly we expect this to be a single file, though it is possible
381 : * some backend will add files onto the list of those that need archiving
382 : * while we are still copying earlier archives
383 : */
384 164 : while (pgarch_readyXlog(xlog))
385 : {
386 62 : int failures = 0;
387 62 : int failures_orphan = 0;
388 :
389 : for (;;)
390 2 : {
391 : struct stat stat_buf;
392 : char pathname[MAXPGPATH];
393 :
394 : /*
395 : * Do not initiate any more archive commands after receiving
396 : * SIGTERM, nor after the postmaster has died unexpectedly. The
397 : * first condition is to try to keep from having init SIGKILL the
398 : * command, and the second is to avoid conflicts with another
399 : * archiver spawned by a newer postmaster.
400 : */
401 64 : if (ShutdownRequestPending || !PostmasterIsAlive())
402 4 : return;
403 :
404 : /*
405 : * Check for barrier events and config update. This is so that
406 : * we'll adopt a new setting for archive_command as soon as
407 : * possible, even if there is a backlog of files to be archived.
408 : */
409 64 : HandlePgArchInterrupts();
410 :
411 : /* can't do anything if not configured ... */
412 64 : if (ArchiveCallbacks->check_configured_cb != NULL &&
413 64 : !ArchiveCallbacks->check_configured_cb(archive_module_state))
414 : {
415 4 : ereport(WARNING,
416 : (errmsg("archive_mode enabled, yet archiving is not configured")));
417 4 : return;
418 : }
419 :
420 : /*
421 : * Since archive status files are not removed in a durable manner,
422 : * a system crash could leave behind .ready files for WAL segments
423 : * that have already been recycled or removed. In this case,
424 : * simply remove the orphan status file and move on. unlink() is
425 : * used here as even on subsequent crashes the same orphan files
426 : * would get removed, so there is no need to worry about
427 : * durability.
428 : */
429 60 : snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog);
430 60 : if (stat(pathname, &stat_buf) != 0 && errno == ENOENT)
431 : {
432 : char xlogready[MAXPGPATH];
433 :
434 0 : StatusFilePath(xlogready, xlog, ".ready");
435 0 : if (unlink(xlogready) == 0)
436 : {
437 0 : ereport(WARNING,
438 : (errmsg("removed orphan archive status file \"%s\"",
439 : xlogready)));
440 :
441 : /* leave loop and move to the next status file */
442 0 : break;
443 : }
444 :
445 0 : if (++failures_orphan >= NUM_ORPHAN_CLEANUP_RETRIES)
446 : {
447 0 : ereport(WARNING,
448 : (errmsg("removal of orphan archive status file \"%s\" failed too many times, will try again later",
449 : xlogready)));
450 :
451 : /* give up cleanup of orphan status files */
452 0 : return;
453 : }
454 :
455 : /* wait a bit before retrying */
456 0 : pg_usleep(1000000L);
457 0 : continue;
458 : }
459 :
460 60 : if (pgarch_archiveXlog(xlog))
461 : {
462 : /* successful */
463 58 : pgarch_archiveDone(xlog);
464 :
465 : /*
466 : * Tell the cumulative stats system about the WAL file that we
467 : * successfully archived
468 : */
469 58 : pgstat_report_archiver(xlog, false);
470 :
471 58 : break; /* out of inner retry loop */
472 : }
473 : else
474 : {
475 : /*
476 : * Tell the cumulative stats system about the WAL file that we
477 : * failed to archive
478 : */
479 2 : pgstat_report_archiver(xlog, true);
480 :
481 2 : if (++failures >= NUM_ARCHIVE_RETRIES)
482 : {
483 0 : ereport(WARNING,
484 : (errmsg("archiving write-ahead log file \"%s\" failed too many times, will try again later",
485 : xlog)));
486 0 : return; /* give up archiving for now */
487 : }
488 2 : pg_usleep(1000000L); /* wait a bit before retrying */
489 : }
490 : }
491 : }
492 : }
493 :
494 : /*
495 : * pgarch_archiveXlog
496 : *
497 : * Invokes archive_file_cb to copy one archive file to wherever it should go
498 : *
499 : * Returns true if successful
500 : */
501 : static bool
502 60 : pgarch_archiveXlog(char *xlog)
503 : {
504 : char pathname[MAXPGPATH];
505 : char activitymsg[MAXFNAMELEN + 16];
506 : bool ret;
507 :
508 60 : snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog);
509 :
510 : /* Report archive activity in PS display */
511 60 : snprintf(activitymsg, sizeof(activitymsg), "archiving %s", xlog);
512 60 : set_ps_display(activitymsg);
513 :
514 60 : ret = ArchiveCallbacks->archive_file_cb(archive_module_state, xlog, pathname);
515 60 : if (ret)
516 58 : snprintf(activitymsg, sizeof(activitymsg), "last was %s", xlog);
517 : else
518 2 : snprintf(activitymsg, sizeof(activitymsg), "failed on %s", xlog);
519 60 : set_ps_display(activitymsg);
520 :
521 60 : return ret;
522 : }
523 :
524 : /*
525 : * pgarch_readyXlog
526 : *
527 : * Return name of the oldest xlog file that has not yet been archived.
528 : * No notification is set that file archiving is now in progress, so
529 : * this would need to be extended if multiple concurrent archival
530 : * tasks were created. If a failure occurs, we will completely
531 : * re-copy the file at the next available opportunity.
532 : *
533 : * It is important that we return the oldest, so that we archive xlogs
534 : * in order that they were written, for two reasons:
535 : * 1) to maintain the sequential chain of xlogs required for recovery
536 : * 2) because the oldest ones will sooner become candidates for
537 : * recycling at time of checkpoint
538 : *
539 : * NOTE: the "oldest" comparison will consider any .history file to be older
540 : * than any other file except another .history file. Segments on a timeline
541 : * with a smaller ID will be older than all segments on a timeline with a
542 : * larger ID; the net result being that past timelines are given higher
543 : * priority for archiving. This seems okay, or at least not obviously worth
544 : * changing.
545 : */
546 : static bool
547 164 : pgarch_readyXlog(char *xlog)
548 : {
549 : char XLogArchiveStatusDir[MAXPGPATH];
550 : DIR *rldir;
551 : struct dirent *rlde;
552 : bool force_dir_scan;
553 :
554 : /*
555 : * If a directory scan was requested, clear the stored file names and
556 : * proceed.
557 : */
558 164 : SpinLockAcquire(&PgArch->arch_lck);
559 164 : force_dir_scan = PgArch->force_dir_scan;
560 164 : PgArch->force_dir_scan = false;
561 164 : SpinLockRelease(&PgArch->arch_lck);
562 :
563 164 : if (force_dir_scan)
564 4 : arch_files->arch_files_size = 0;
565 :
566 : /*
567 : * If we still have stored file names from the previous directory scan,
568 : * try to return one of those. We check to make sure the status file is
569 : * still present, as the archive_command for a previous file may have
570 : * already marked it done.
571 : */
572 164 : while (arch_files->arch_files_size > 0)
573 : {
574 : struct stat st;
575 : char status_file[MAXPGPATH];
576 : char *arch_file;
577 :
578 2 : arch_files->arch_files_size--;
579 2 : arch_file = arch_files->arch_files[arch_files->arch_files_size];
580 2 : StatusFilePath(status_file, arch_file, ".ready");
581 :
582 2 : if (stat(status_file, &st) == 0)
583 : {
584 2 : strcpy(xlog, arch_file);
585 2 : return true;
586 : }
587 0 : else if (errno != ENOENT)
588 0 : ereport(ERROR,
589 : (errcode_for_file_access(),
590 : errmsg("could not stat file \"%s\": %m", status_file)));
591 : }
592 :
593 : /* arch_heap is probably empty, but let's make sure */
594 162 : binaryheap_reset(arch_files->arch_heap);
595 :
596 : /*
597 : * Open the archive status directory and read through the list of files
598 : * with the .ready suffix, looking for the earliest files.
599 : */
600 162 : snprintf(XLogArchiveStatusDir, MAXPGPATH, XLOGDIR "/archive_status");
601 162 : rldir = AllocateDir(XLogArchiveStatusDir);
602 :
603 802 : while ((rlde = ReadDir(rldir, XLogArchiveStatusDir)) != NULL)
604 : {
605 640 : int basenamelen = (int) strlen(rlde->d_name) - 6;
606 : char basename[MAX_XFN_CHARS + 1];
607 : char *arch_file;
608 :
609 : /* Ignore entries with unexpected number of characters */
610 640 : if (basenamelen < MIN_XFN_CHARS ||
611 : basenamelen > MAX_XFN_CHARS)
612 578 : continue;
613 :
614 : /* Ignore entries with unexpected characters */
615 280 : if (strspn(rlde->d_name, VALID_XFN_CHARS) < basenamelen)
616 0 : continue;
617 :
618 : /* Ignore anything not suffixed with .ready */
619 280 : if (strcmp(rlde->d_name + basenamelen, ".ready") != 0)
620 218 : continue;
621 :
622 : /* Truncate off the .ready */
623 62 : memcpy(basename, rlde->d_name, basenamelen);
624 62 : basename[basenamelen] = '\0';
625 :
626 : /*
627 : * Store the file in our max-heap if it has a high enough priority.
628 : */
629 62 : if (arch_files->arch_heap->bh_size < NUM_FILES_PER_DIRECTORY_SCAN)
630 : {
631 : /* If the heap isn't full yet, quickly add it. */
632 62 : arch_file = arch_files->arch_filenames[arch_files->arch_heap->bh_size];
633 62 : strcpy(arch_file, basename);
634 62 : binaryheap_add_unordered(arch_files->arch_heap, CStringGetDatum(arch_file));
635 :
636 : /* If we just filled the heap, make it a valid one. */
637 62 : if (arch_files->arch_heap->bh_size == NUM_FILES_PER_DIRECTORY_SCAN)
638 0 : binaryheap_build(arch_files->arch_heap);
639 : }
640 0 : else if (ready_file_comparator(binaryheap_first(arch_files->arch_heap),
641 : CStringGetDatum(basename), NULL) > 0)
642 : {
643 : /*
644 : * Remove the lowest priority file and add the current one to the
645 : * heap.
646 : */
647 0 : arch_file = DatumGetCString(binaryheap_remove_first(arch_files->arch_heap));
648 0 : strcpy(arch_file, basename);
649 0 : binaryheap_add(arch_files->arch_heap, CStringGetDatum(arch_file));
650 : }
651 : }
652 162 : FreeDir(rldir);
653 :
654 : /* If no files were found, simply return. */
655 162 : if (arch_files->arch_heap->bh_size == 0)
656 102 : return false;
657 :
658 : /*
659 : * If we didn't fill the heap, we didn't make it a valid one. Do that
660 : * now.
661 : */
662 60 : if (arch_files->arch_heap->bh_size < NUM_FILES_PER_DIRECTORY_SCAN)
663 60 : binaryheap_build(arch_files->arch_heap);
664 :
665 : /*
666 : * Fill arch_files array with the files to archive in ascending order of
667 : * priority.
668 : */
669 60 : arch_files->arch_files_size = arch_files->arch_heap->bh_size;
670 122 : for (int i = 0; i < arch_files->arch_files_size; i++)
671 62 : arch_files->arch_files[i] = DatumGetCString(binaryheap_remove_first(arch_files->arch_heap));
672 :
673 : /* Return the highest priority file. */
674 60 : arch_files->arch_files_size--;
675 60 : strcpy(xlog, arch_files->arch_files[arch_files->arch_files_size]);
676 :
677 60 : return true;
678 : }
679 :
680 : /*
681 : * ready_file_comparator
682 : *
683 : * Compares the archival priority of the given files to archive. If "a"
684 : * has a higher priority than "b", a negative value will be returned. If
685 : * "b" has a higher priority than "a", a positive value will be returned.
686 : * If "a" and "b" have equivalent values, 0 will be returned.
687 : */
688 : static int
689 2 : ready_file_comparator(Datum a, Datum b, void *arg)
690 : {
691 2 : char *a_str = DatumGetCString(a);
692 2 : char *b_str = DatumGetCString(b);
693 2 : bool a_history = IsTLHistoryFileName(a_str);
694 2 : bool b_history = IsTLHistoryFileName(b_str);
695 :
696 : /* Timeline history files always have the highest priority. */
697 2 : if (a_history != b_history)
698 0 : return a_history ? -1 : 1;
699 :
700 : /* Priority is given to older files. */
701 2 : return strcmp(a_str, b_str);
702 : }
703 :
704 : /*
705 : * PgArchForceDirScan
706 : *
707 : * When called, the next call to pgarch_readyXlog() will perform a
708 : * directory scan. This is useful for ensuring that important files such
709 : * as timeline history files are archived as quickly as possible.
710 : */
711 : void
712 22 : PgArchForceDirScan(void)
713 : {
714 22 : SpinLockAcquire(&PgArch->arch_lck);
715 22 : PgArch->force_dir_scan = true;
716 22 : SpinLockRelease(&PgArch->arch_lck);
717 22 : }
718 :
719 : /*
720 : * pgarch_archiveDone
721 : *
722 : * Emit notification that an xlog file has been successfully archived.
723 : * We do this by renaming the status file from NNN.ready to NNN.done.
724 : * Eventually, a checkpoint process will notice this and delete both the
725 : * NNN.done file and the xlog file itself.
726 : */
727 : static void
728 58 : pgarch_archiveDone(char *xlog)
729 : {
730 : char rlogready[MAXPGPATH];
731 : char rlogdone[MAXPGPATH];
732 :
733 58 : StatusFilePath(rlogready, xlog, ".ready");
734 58 : StatusFilePath(rlogdone, xlog, ".done");
735 :
736 : /*
737 : * To avoid extra overhead, we don't durably rename the .ready file to
738 : * .done. Archive commands and libraries must gracefully handle attempts
739 : * to re-archive files (e.g., if the server crashes just before this
740 : * function is called), so it should be okay if the .ready file reappears
741 : * after a crash.
742 : */
743 58 : if (rename(rlogready, rlogdone) < 0)
744 0 : ereport(WARNING,
745 : (errcode_for_file_access(),
746 : errmsg("could not rename file \"%s\" to \"%s\": %m",
747 : rlogready, rlogdone)));
748 58 : }
749 :
750 :
751 : /*
752 : * pgarch_die
753 : *
754 : * Exit-time cleanup handler
755 : */
756 : static void
757 24 : pgarch_die(int code, Datum arg)
758 : {
759 24 : PgArch->pgprocno = INVALID_PGPROCNO;
760 24 : }
761 :
762 : /*
763 : * Interrupt handler for WAL archiver process.
764 : *
765 : * This is called in the loops pgarch_MainLoop and pgarch_ArchiverCopyLoop.
766 : * It checks for barrier events, config update and request for logging of
767 : * memory contexts, but not shutdown request because how to handle
768 : * shutdown request is different between those loops.
769 : */
770 : static void
771 170 : HandlePgArchInterrupts(void)
772 : {
773 170 : if (ProcSignalBarrierPending)
774 2 : ProcessProcSignalBarrier();
775 :
776 : /* Perform logging of memory contexts of this process */
777 170 : if (LogMemoryContextPending)
778 0 : ProcessLogMemoryContextInterrupt();
779 :
780 170 : if (ConfigReloadPending)
781 : {
782 4 : char *archiveLib = pstrdup(XLogArchiveLibrary);
783 : bool archiveLibChanged;
784 :
785 4 : ConfigReloadPending = false;
786 4 : ProcessConfigFile(PGC_SIGHUP);
787 :
788 4 : if (XLogArchiveLibrary[0] != '\0' && XLogArchiveCommand[0] != '\0')
789 0 : ereport(ERROR,
790 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
791 : errmsg("both archive_command and archive_library set"),
792 : errdetail("Only one of archive_command, archive_library may be set.")));
793 :
794 4 : archiveLibChanged = strcmp(XLogArchiveLibrary, archiveLib) != 0;
795 4 : pfree(archiveLib);
796 :
797 4 : if (archiveLibChanged)
798 : {
799 : /*
800 : * Ideally, we would simply unload the previous archive module and
801 : * load the new one, but there is presently no mechanism for
802 : * unloading a library (see the comment above
803 : * internal_load_library()). To deal with this, we simply restart
804 : * the archiver. The new archive module will be loaded when the
805 : * new archiver process starts up. Note that this triggers the
806 : * module's shutdown callback, if defined.
807 : */
808 0 : ereport(LOG,
809 : (errmsg("restarting archiver process because value of "
810 : "archive_library was changed")));
811 :
812 0 : proc_exit(0);
813 : }
814 : }
815 170 : }
816 :
817 : /*
818 : * LoadArchiveLibrary
819 : *
820 : * Loads the archiving callbacks into our local ArchiveCallbacks.
821 : */
822 : static void
823 24 : LoadArchiveLibrary(void)
824 : {
825 : ArchiveModuleInit archive_init;
826 :
827 24 : if (XLogArchiveLibrary[0] != '\0' && XLogArchiveCommand[0] != '\0')
828 0 : ereport(ERROR,
829 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
830 : errmsg("both archive_command and archive_library set"),
831 : errdetail("Only one of archive_command, archive_library may be set.")));
832 :
833 : /*
834 : * If shell archiving is enabled, use our special initialization function.
835 : * Otherwise, load the library and call its _PG_archive_module_init().
836 : */
837 24 : if (XLogArchiveLibrary[0] == '\0')
838 22 : archive_init = shell_archive_init;
839 : else
840 2 : archive_init = (ArchiveModuleInit)
841 2 : load_external_function(XLogArchiveLibrary,
842 : "_PG_archive_module_init", false, NULL);
843 :
844 24 : if (archive_init == NULL)
845 0 : ereport(ERROR,
846 : (errmsg("archive modules have to define the symbol %s", "_PG_archive_module_init")));
847 :
848 24 : ArchiveCallbacks = (*archive_init) ();
849 :
850 24 : if (ArchiveCallbacks->archive_file_cb == NULL)
851 0 : ereport(ERROR,
852 : (errmsg("archive modules must register an archive callback")));
853 :
854 24 : archive_module_state = (ArchiveModuleState *) palloc0(sizeof(ArchiveModuleState));
855 24 : if (ArchiveCallbacks->startup_cb != NULL)
856 2 : ArchiveCallbacks->startup_cb(archive_module_state);
857 :
858 24 : before_shmem_exit(pgarch_call_module_shutdown_cb, 0);
859 24 : }
860 :
861 : /*
862 : * Call the shutdown callback of the loaded archive module, if defined.
863 : */
864 : static void
865 24 : pgarch_call_module_shutdown_cb(int code, Datum arg)
866 : {
867 24 : if (ArchiveCallbacks->shutdown_cb != NULL)
868 24 : ArchiveCallbacks->shutdown_cb(archive_module_state);
869 24 : }
|