24
24
* are treated as not a crash but approximately normal termination;
25
25
* the walsender will exit quickly without sending any more XLOG records.
26
26
*
27
- * If the server is shut down, postmaster sends us SIGUSR2 after all
28
- * regular backends have exited and the shutdown checkpoint has been written.
29
- * This instructs walsender to send any outstanding WAL, including the
30
- * shutdown checkpoint record, wait for it to be replicated to the standby,
31
- * and then exit.
27
+ * If the server is shut down, checkpointer sends us
28
+ * PROCSIG_WALSND_INIT_STOPPING after all regular backends have exited. If
29
+ * the backend is idle or runs an SQL query this causes the backend to
30
+ * shutdown, if logical replication is in progress all existing WAL records
31
+ * are processed followed by a shutdown. Otherwise this causes the walsender
32
+ * to switch to the "stopping" state. In this state, the walsender will reject
33
+ * any further replication commands. The checkpointer begins the shutdown
34
+ * checkpoint once all walsenders are confirmed as stopping. When the shutdown
35
+ * checkpoint finishes, the postmaster sends us SIGUSR2. This instructs
36
+ * walsender to send any outstanding WAL, including the shutdown checkpoint
37
+ * record, wait for it to be replicated to the standby, and then exit.
32
38
*
33
39
*
34
40
* Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group
@@ -171,13 +177,14 @@ static bool WalSndCaughtUp = false;
171
177
172
178
/* Flags set by signal handlers for later service in main loop */
173
179
static volatile sig_atomic_t got_SIGHUP = false;
174
- static volatile sig_atomic_t walsender_ready_to_stop = false;
180
+ static volatile sig_atomic_t got_SIGUSR2 = false;
181
+ static volatile sig_atomic_t got_STOPPING = false;
175
182
176
183
/*
177
- * This is set while we are streaming. When not set, SIGUSR2 signal will be
178
- * handled like SIGTERM. When set, the main loop is responsible for checking
179
- * walsender_ready_to_stop and terminating when it's set (after streaming any
180
- * remaining WAL).
184
+ * This is set while we are streaming. When not set
185
+ * PROCSIG_WALSND_INIT_STOPPING signal will be handled like SIGTERM. When set,
186
+ * the main loop is responsible for checking got_STOPPING and terminating when
187
+ * it's set (after streaming any remaining WAL).
181
188
*/
182
189
static volatile sig_atomic_t replication_active = false;
183
190
@@ -264,7 +271,8 @@ WalSndErrorCleanup(void)
264
271
ReplicationSlotRelease ();
265
272
266
273
replication_active = false;
267
- if (walsender_ready_to_stop )
274
+
275
+ if (got_STOPPING || got_SIGUSR2 )
268
276
proc_exit (0 );
269
277
270
278
/* Revert back to startup state */
@@ -671,7 +679,7 @@ StartReplication(StartReplicationCmd *cmd)
671
679
WalSndLoop (XLogSendPhysical );
672
680
673
681
replication_active = false;
674
- if (walsender_ready_to_stop )
682
+ if (got_STOPPING )
675
683
proc_exit (0 );
676
684
WalSndSetState (WALSNDSTATE_STARTUP );
677
685
@@ -970,7 +978,7 @@ StartLogicalReplication(StartReplicationCmd *cmd)
970
978
{
971
979
ereport (LOG ,
972
980
(errmsg ("terminating walsender process after promotion" )));
973
- walsender_ready_to_stop = true;
981
+ got_STOPPING = true;
974
982
}
975
983
976
984
WalSndSetState (WALSNDSTATE_CATCHUP );
@@ -1024,7 +1032,7 @@ StartLogicalReplication(StartReplicationCmd *cmd)
1024
1032
ReplicationSlotRelease ();
1025
1033
1026
1034
replication_active = false;
1027
- if (walsender_ready_to_stop )
1035
+ if (got_STOPPING )
1028
1036
proc_exit (0 );
1029
1037
WalSndSetState (WALSNDSTATE_STARTUP );
1030
1038
@@ -1204,6 +1212,14 @@ WalSndWaitForWal(XLogRecPtr loc)
1204
1212
/* Check for input from the client */
1205
1213
ProcessRepliesIfAny ();
1206
1214
1215
+ /*
1216
+ * If we're shutting down, trigger pending WAL to be written out,
1217
+ * otherwise we'd possibly end up waiting for WAL that never gets
1218
+ * written, because walwriter has shut down already.
1219
+ */
1220
+ if (got_STOPPING )
1221
+ XLogBackgroundFlush ();
1222
+
1207
1223
/* Update our idea of the currently flushed position. */
1208
1224
if (!RecoveryInProgress ())
1209
1225
RecentFlushPtr = GetFlushRecPtr ();
@@ -1219,7 +1235,7 @@ WalSndWaitForWal(XLogRecPtr loc)
1219
1235
* RecentFlushPtr, so we can send all remaining data before shutting
1220
1236
* down.
1221
1237
*/
1222
- if (walsender_ready_to_stop )
1238
+ if (got_STOPPING )
1223
1239
break ;
1224
1240
1225
1241
/*
@@ -1289,6 +1305,22 @@ exec_replication_command(const char *cmd_string)
1289
1305
MemoryContext cmd_context ;
1290
1306
MemoryContext old_context ;
1291
1307
1308
+ /*
1309
+ * If WAL sender has been told that shutdown is getting close, switch its
1310
+ * status accordingly to handle the next replication commands correctly.
1311
+ */
1312
+ if (got_STOPPING )
1313
+ WalSndSetState (WALSNDSTATE_STOPPING );
1314
+
1315
+ /*
1316
+ * Throw error if in stopping mode. We need prevent commands that could
1317
+ * generate WAL while the shutdown checkpoint is being written. To be
1318
+ * safe, we just prohibit all new commands.
1319
+ */
1320
+ if (MyWalSnd -> state == WALSNDSTATE_STOPPING )
1321
+ ereport (ERROR ,
1322
+ (errmsg ("cannot execute new commands while WAL sender is in stopping mode" )));
1323
+
1292
1324
/*
1293
1325
* Log replication command if log_replication_commands is enabled. Even
1294
1326
* when it's disabled, log the command with DEBUG1 level for backward
@@ -1884,7 +1916,7 @@ WalSndLoop(WalSndSendDataCallback send_data)
1884
1916
* normal termination at shutdown, or a promotion, the walsender
1885
1917
* is not sure which.
1886
1918
*/
1887
- if (walsender_ready_to_stop )
1919
+ if (got_SIGUSR2 )
1888
1920
WalSndDone (send_data );
1889
1921
}
1890
1922
@@ -2193,6 +2225,10 @@ XLogSendPhysical(void)
2193
2225
XLogRecPtr endptr ;
2194
2226
Size nbytes ;
2195
2227
2228
+ /* If requested switch the WAL sender to the stopping state. */
2229
+ if (got_STOPPING )
2230
+ WalSndSetState (WALSNDSTATE_STOPPING );
2231
+
2196
2232
if (streamingDoneSending )
2197
2233
{
2198
2234
WalSndCaughtUp = true;
@@ -2452,7 +2488,16 @@ XLogSendLogical(void)
2452
2488
* point, then we're caught up.
2453
2489
*/
2454
2490
if (logical_decoding_ctx -> reader -> EndRecPtr >= GetFlushRecPtr ())
2491
+ {
2455
2492
WalSndCaughtUp = true;
2493
+
2494
+ /*
2495
+ * Have WalSndLoop() terminate the connection in an orderly
2496
+ * manner, after writing out all the pending data.
2497
+ */
2498
+ if (got_STOPPING )
2499
+ got_SIGUSR2 = true;
2500
+ }
2456
2501
}
2457
2502
2458
2503
/* Update shared memory status */
@@ -2563,6 +2608,26 @@ WalSndRqstFileReload(void)
2563
2608
}
2564
2609
}
2565
2610
2611
+ /*
2612
+ * Handle PROCSIG_WALSND_INIT_STOPPING signal.
2613
+ */
2614
+ void
2615
+ HandleWalSndInitStopping (void )
2616
+ {
2617
+ Assert (am_walsender );
2618
+
2619
+ /*
2620
+ * If replication has not yet started, die like with SIGTERM. If
2621
+ * replication is active, only set a flag and wake up the main loop. It
2622
+ * will send any outstanding WAL, wait for it to be replicated to the
2623
+ * standby, and then exit gracefully.
2624
+ */
2625
+ if (!replication_active )
2626
+ kill (MyProcPid , SIGTERM );
2627
+ else
2628
+ got_STOPPING = true;
2629
+ }
2630
+
2566
2631
/* SIGHUP: set flag to re-read config file at next convenient time */
2567
2632
static void
2568
2633
WalSndSigHupHandler (SIGNAL_ARGS )
@@ -2576,22 +2641,17 @@ WalSndSigHupHandler(SIGNAL_ARGS)
2576
2641
errno = save_errno ;
2577
2642
}
2578
2643
2579
- /* SIGUSR2: set flag to do a last cycle and shut down afterwards */
2644
+ /*
2645
+ * SIGUSR2: set flag to do a last cycle and shut down afterwards. The WAL
2646
+ * sender should already have been switched to WALSNDSTATE_STOPPING at
2647
+ * this point.
2648
+ */
2580
2649
static void
2581
2650
WalSndLastCycleHandler (SIGNAL_ARGS )
2582
2651
{
2583
2652
int save_errno = errno ;
2584
2653
2585
- /*
2586
- * If replication has not yet started, die like with SIGTERM. If
2587
- * replication is active, only set a flag and wake up the main loop. It
2588
- * will send any outstanding WAL, wait for it to be replicated to the
2589
- * standby, and then exit gracefully.
2590
- */
2591
- if (!replication_active )
2592
- kill (MyProcPid , SIGTERM );
2593
-
2594
- walsender_ready_to_stop = true;
2654
+ got_SIGUSR2 = true;
2595
2655
SetLatch (MyLatch );
2596
2656
2597
2657
errno = save_errno ;
@@ -2689,6 +2749,77 @@ WalSndWakeup(void)
2689
2749
}
2690
2750
}
2691
2751
2752
+ /*
2753
+ * Signal all walsenders to move to stopping state.
2754
+ *
2755
+ * This will trigger walsenders to move to a state where no further WAL can be
2756
+ * generated. See this file's header for details.
2757
+ */
2758
+ void
2759
+ WalSndInitStopping (void )
2760
+ {
2761
+ int i ;
2762
+
2763
+ for (i = 0 ; i < max_wal_senders ; i ++ )
2764
+ {
2765
+ WalSnd * walsnd = & WalSndCtl -> walsnds [i ];
2766
+ pid_t pid ;
2767
+
2768
+ SpinLockAcquire (& walsnd -> mutex );
2769
+ pid = walsnd -> pid ;
2770
+ SpinLockRelease (& walsnd -> mutex );
2771
+
2772
+ if (pid == 0 )
2773
+ continue ;
2774
+
2775
+ SendProcSignal (pid , PROCSIG_WALSND_INIT_STOPPING , InvalidBackendId );
2776
+ }
2777
+ }
2778
+
2779
+ /*
2780
+ * Wait that all the WAL senders have quit or reached the stopping state. This
2781
+ * is used by the checkpointer to control when the shutdown checkpoint can
2782
+ * safely be performed.
2783
+ */
2784
+ void
2785
+ WalSndWaitStopping (void )
2786
+ {
2787
+ for (;;)
2788
+ {
2789
+ int i ;
2790
+ bool all_stopped = true;
2791
+
2792
+ for (i = 0 ; i < max_wal_senders ; i ++ )
2793
+ {
2794
+ WalSndState state ;
2795
+ WalSnd * walsnd = & WalSndCtl -> walsnds [i ];
2796
+
2797
+ SpinLockAcquire (& walsnd -> mutex );
2798
+
2799
+ if (walsnd -> pid == 0 )
2800
+ {
2801
+ SpinLockRelease (& walsnd -> mutex );
2802
+ continue ;
2803
+ }
2804
+
2805
+ state = walsnd -> state ;
2806
+ SpinLockRelease (& walsnd -> mutex );
2807
+
2808
+ if (state != WALSNDSTATE_STOPPING )
2809
+ {
2810
+ all_stopped = false;
2811
+ break ;
2812
+ }
2813
+ }
2814
+
2815
+ /* safe to leave if confirmation is done for all WAL senders */
2816
+ if (all_stopped )
2817
+ return ;
2818
+
2819
+ pg_usleep (10000L ); /* wait for 10 msec */
2820
+ }
2821
+ }
2822
+
2692
2823
/* Set state for current walsender (only called in walsender) */
2693
2824
void
2694
2825
WalSndSetState (WalSndState state )
@@ -2722,6 +2853,8 @@ WalSndGetStateString(WalSndState state)
2722
2853
return "catchup" ;
2723
2854
case WALSNDSTATE_STREAMING :
2724
2855
return "streaming" ;
2856
+ case WALSNDSTATE_STOPPING :
2857
+ return "stopping" ;
2725
2858
}
2726
2859
return "UNKNOWN" ;
2727
2860
}
0 commit comments