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