10
10
* fill WAL segments; the checkpointer itself doesn't watch for the
11
11
* condition.)
12
12
*
13
- * Normal termination is by SIGUSR2, which instructs the checkpointer to
14
- * execute a shutdown checkpoint and then exit(0). (All backends must be
15
- * stopped before SIGUSR2 is issued!) Emergency termination is by SIGQUIT;
16
- * like any backend, the checkpointer will simply abort and exit on SIGQUIT.
13
+ * The normal termination sequence is that checkpointer is instructed to
14
+ * execute the shutdown checkpoint by SIGINT. After that checkpointer waits
15
+ * to be terminated via SIGUSR2, which instructs the checkpointer to exit(0).
16
+ * All backends must be stopped before SIGINT or SIGUSR2 is issued!
17
+ *
18
+ * Emergency termination is by SIGQUIT; like any backend, the checkpointer
19
+ * will simply abort and exit on SIGQUIT.
17
20
*
18
21
* If the checkpointer exits unexpectedly, the postmaster treats that the same
19
22
* as a backend crash: shared memory may be corrupted, so remaining backends
51
54
#include "storage/fd.h"
52
55
#include "storage/ipc.h"
53
56
#include "storage/lwlock.h"
57
+ #include "storage/pmsignal.h"
54
58
#include "storage/proc.h"
55
59
#include "storage/procsignal.h"
56
60
#include "storage/shmem.h"
@@ -141,6 +145,7 @@ double CheckPointCompletionTarget = 0.9;
141
145
* Private state
142
146
*/
143
147
static bool ckpt_active = false;
148
+ static volatile sig_atomic_t ShutdownXLOGPending = false;
144
149
145
150
/* these values are valid when ckpt_active is true: */
146
151
static pg_time_t ckpt_start_time ;
@@ -159,6 +164,9 @@ static bool ImmediateCheckpointRequested(void);
159
164
static bool CompactCheckpointerRequestQueue (void );
160
165
static void UpdateSharedMemoryConfig (void );
161
166
167
+ /* Signal handlers */
168
+ static void ReqShutdownXLOG (SIGNAL_ARGS );
169
+
162
170
163
171
/*
164
172
* Main entry point for checkpointer process
@@ -188,7 +196,7 @@ CheckpointerMain(char *startup_data, size_t startup_data_len)
188
196
* tell us it's okay to shut down (via SIGUSR2).
189
197
*/
190
198
pqsignal (SIGHUP , SignalHandlerForConfigReload );
191
- pqsignal (SIGINT , SIG_IGN );
199
+ pqsignal (SIGINT , ReqShutdownXLOG );
192
200
pqsignal (SIGTERM , SIG_IGN ); /* ignore SIGTERM */
193
201
/* SIGQUIT handler was already set up by InitPostmasterChild */
194
202
pqsignal (SIGALRM , SIG_IGN );
@@ -211,8 +219,11 @@ CheckpointerMain(char *startup_data, size_t startup_data_len)
211
219
* process during a normal shutdown, and since checkpointer is shut down
212
220
* very late...
213
221
*
214
- * Walsenders are shut down after the checkpointer, but currently don't
215
- * report stats. If that changes, we need a more complicated solution.
222
+ * While e.g. walsenders are active after the shutdown checkpoint has been
223
+ * written (and thus could produce more stats), checkpointer stays around
224
+ * after the shutdown checkpoint has been written. postmaster will only
225
+ * signal checkpointer to exit after all processes that could emit stats
226
+ * have been shut down.
216
227
*/
217
228
before_shmem_exit (pgstat_before_server_shutdown , 0 );
218
229
@@ -327,7 +338,8 @@ CheckpointerMain(char *startup_data, size_t startup_data_len)
327
338
ProcGlobal -> checkpointerProc = MyProcNumber ;
328
339
329
340
/*
330
- * Loop forever
341
+ * Loop until we've been asked to write the shutdown checkpoint or
342
+ * terminate.
331
343
*/
332
344
for (;;)
333
345
{
@@ -346,7 +358,10 @@ CheckpointerMain(char *startup_data, size_t startup_data_len)
346
358
* Process any requests or signals received recently.
347
359
*/
348
360
AbsorbSyncRequests ();
361
+
349
362
HandleCheckpointerInterrupts ();
363
+ if (ShutdownXLOGPending || ShutdownRequestPending )
364
+ break ;
350
365
351
366
/*
352
367
* Detect a pending checkpoint request by checking whether the flags
@@ -517,8 +532,13 @@ CheckpointerMain(char *startup_data, size_t startup_data_len)
517
532
518
533
ckpt_active = false;
519
534
520
- /* We may have received an interrupt during the checkpoint. */
535
+ /*
536
+ * We may have received an interrupt during the checkpoint and the
537
+ * latch might have been reset (e.g. in CheckpointWriteDelay).
538
+ */
521
539
HandleCheckpointerInterrupts ();
540
+ if (ShutdownXLOGPending || ShutdownRequestPending )
541
+ break ;
522
542
}
523
543
524
544
/* Check for archive_timeout and switch xlog files if necessary. */
@@ -557,6 +577,57 @@ CheckpointerMain(char *startup_data, size_t startup_data_len)
557
577
cur_timeout * 1000L /* convert to ms */ ,
558
578
WAIT_EVENT_CHECKPOINTER_MAIN );
559
579
}
580
+
581
+ /*
582
+ * From here on, elog(ERROR) should end with exit(1), not send control
583
+ * back to the sigsetjmp block above.
584
+ */
585
+ ExitOnAnyError = true;
586
+
587
+ if (ShutdownXLOGPending )
588
+ {
589
+ /*
590
+ * Close down the database.
591
+ *
592
+ * Since ShutdownXLOG() creates restartpoint or checkpoint, and
593
+ * updates the statistics, increment the checkpoint request and flush
594
+ * out pending statistic.
595
+ */
596
+ PendingCheckpointerStats .num_requested ++ ;
597
+ ShutdownXLOG (0 , 0 );
598
+ pgstat_report_checkpointer ();
599
+ pgstat_report_wal (true);
600
+
601
+ /*
602
+ * Tell postmaster that we're done.
603
+ */
604
+ SendPostmasterSignal (PMSIGNAL_XLOG_IS_SHUTDOWN );
605
+ ShutdownXLOGPending = false;
606
+ }
607
+
608
+ /*
609
+ * Wait until we're asked to shut down. By separating the writing of the
610
+ * shutdown checkpoint from checkpointer exiting, checkpointer can perform
611
+ * some should-be-as-late-as-possible work like writing out stats.
612
+ */
613
+ for (;;)
614
+ {
615
+ /* Clear any already-pending wakeups */
616
+ ResetLatch (MyLatch );
617
+
618
+ HandleCheckpointerInterrupts ();
619
+
620
+ if (ShutdownRequestPending )
621
+ break ;
622
+
623
+ (void ) WaitLatch (MyLatch ,
624
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH ,
625
+ 0 ,
626
+ WAIT_EVENT_CHECKPOINTER_SHUTDOWN );
627
+ }
628
+
629
+ /* Normal exit from the checkpointer is here */
630
+ proc_exit (0 ); /* done */
560
631
}
561
632
562
633
/*
@@ -586,29 +657,6 @@ HandleCheckpointerInterrupts(void)
586
657
*/
587
658
UpdateSharedMemoryConfig ();
588
659
}
589
- if (ShutdownRequestPending )
590
- {
591
- /*
592
- * From here on, elog(ERROR) should end with exit(1), not send control
593
- * back to the sigsetjmp block above
594
- */
595
- ExitOnAnyError = true;
596
-
597
- /*
598
- * Close down the database.
599
- *
600
- * Since ShutdownXLOG() creates restartpoint or checkpoint, and
601
- * updates the statistics, increment the checkpoint request and flush
602
- * out pending statistic.
603
- */
604
- PendingCheckpointerStats .num_requested ++ ;
605
- ShutdownXLOG (0 , 0 );
606
- pgstat_report_checkpointer ();
607
- pgstat_report_wal (true);
608
-
609
- /* Normal exit from the checkpointer is here */
610
- proc_exit (0 ); /* done */
611
- }
612
660
613
661
/* Perform logging of memory contexts of this process */
614
662
if (LogMemoryContextPending )
@@ -729,6 +777,7 @@ CheckpointWriteDelay(int flags, double progress)
729
777
* in which case we just try to catch up as quickly as possible.
730
778
*/
731
779
if (!(flags & CHECKPOINT_IMMEDIATE ) &&
780
+ !ShutdownXLOGPending &&
732
781
!ShutdownRequestPending &&
733
782
!ImmediateCheckpointRequested () &&
734
783
IsCheckpointOnSchedule (progress ))
@@ -857,6 +906,20 @@ IsCheckpointOnSchedule(double progress)
857
906
}
858
907
859
908
909
+ /* --------------------------------
910
+ * signal handler routines
911
+ * --------------------------------
912
+ */
913
+
914
+ /* SIGINT: set flag to trigger writing of shutdown checkpoint */
915
+ static void
916
+ ReqShutdownXLOG (SIGNAL_ARGS )
917
+ {
918
+ ShutdownXLOGPending = true;
919
+ SetLatch (MyLatch );
920
+ }
921
+
922
+
860
923
/* --------------------------------
861
924
* communication with backends
862
925
* --------------------------------
0 commit comments