@@ -154,9 +154,12 @@ static StringInfoData output_message;
154
154
static StringInfoData reply_message ;
155
155
static StringInfoData tmpbuf ;
156
156
157
+ /* Timestamp of last ProcessRepliesIfAny(). */
158
+ static TimestampTz last_processing = 0 ;
159
+
157
160
/*
158
- * Timestamp of the last receipt of the reply from the standby. Set to 0 if
159
- * wal_sender_timeout doesn't need to be active.
161
+ * Timestamp of last ProcessRepliesIfAny() that saw a reply from the
162
+ * standby. Set to 0 if wal_sender_timeout doesn't need to be active.
160
163
*/
161
164
static TimestampTz last_reply_timestamp = 0 ;
162
165
@@ -213,8 +216,8 @@ static void ProcessStandbyReplyMessage(void);
213
216
static void ProcessStandbyHSFeedbackMessage (void );
214
217
static void ProcessRepliesIfAny (void );
215
218
static void WalSndKeepalive (bool requestReply );
216
- static void WalSndKeepaliveIfNecessary (TimestampTz now );
217
- static void WalSndCheckTimeOut (TimestampTz now );
219
+ static void WalSndKeepaliveIfNecessary (void );
220
+ static void WalSndCheckTimeOut (void );
218
221
static long WalSndComputeSleeptime (TimestampTz now );
219
222
static void WalSndPrepareWrite (LogicalDecodingContext * ctx , XLogRecPtr lsn , TransactionId xid , bool last_write );
220
223
static void WalSndWriteData (LogicalDecodingContext * ctx , XLogRecPtr lsn , TransactionId xid , bool last_write );
@@ -1117,18 +1120,16 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
1117
1120
/* Check for input from the client */
1118
1121
ProcessRepliesIfAny ();
1119
1122
1120
- now = GetCurrentTimestamp ();
1121
-
1122
1123
/* die if timeout was reached */
1123
- WalSndCheckTimeOut (now );
1124
+ WalSndCheckTimeOut ();
1124
1125
1125
1126
/* Send keepalive if the time has come */
1126
- WalSndKeepaliveIfNecessary (now );
1127
+ WalSndKeepaliveIfNecessary ();
1127
1128
1128
1129
if (!pq_is_send_pending ())
1129
1130
break ;
1130
1131
1131
- sleeptime = WalSndComputeSleeptime (now );
1132
+ sleeptime = WalSndComputeSleeptime (GetCurrentTimestamp () );
1132
1133
1133
1134
wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
1134
1135
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT ;
@@ -1198,7 +1199,6 @@ WalSndWaitForWal(XLogRecPtr loc)
1198
1199
for (;;)
1199
1200
{
1200
1201
long sleeptime ;
1201
- TimestampTz now ;
1202
1202
1203
1203
/*
1204
1204
* Emergency bailout if postmaster has died. This is to avoid the
@@ -1283,13 +1283,11 @@ WalSndWaitForWal(XLogRecPtr loc)
1283
1283
!pq_is_send_pending ())
1284
1284
break ;
1285
1285
1286
- now = GetCurrentTimestamp ();
1287
-
1288
1286
/* die if timeout was reached */
1289
- WalSndCheckTimeOut (now );
1287
+ WalSndCheckTimeOut ();
1290
1288
1291
1289
/* Send keepalive if the time has come */
1292
- WalSndKeepaliveIfNecessary (now );
1290
+ WalSndKeepaliveIfNecessary ();
1293
1291
1294
1292
/*
1295
1293
* Sleep until something happens or we time out. Also wait for the
@@ -1298,7 +1296,7 @@ WalSndWaitForWal(XLogRecPtr loc)
1298
1296
* new WAL to be generated. (But if we have nothing to send, we don't
1299
1297
* want to wake on socket-writable.)
1300
1298
*/
1301
- sleeptime = WalSndComputeSleeptime (now );
1299
+ sleeptime = WalSndComputeSleeptime (GetCurrentTimestamp () );
1302
1300
1303
1301
wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
1304
1302
WL_SOCKET_READABLE | WL_TIMEOUT ;
@@ -1438,6 +1436,8 @@ ProcessRepliesIfAny(void)
1438
1436
int r ;
1439
1437
bool received = false;
1440
1438
1439
+ last_processing = GetCurrentTimestamp ();
1440
+
1441
1441
for (;;)
1442
1442
{
1443
1443
pq_startmsgread ();
@@ -1525,7 +1525,7 @@ ProcessRepliesIfAny(void)
1525
1525
*/
1526
1526
if (received )
1527
1527
{
1528
- last_reply_timestamp = GetCurrentTimestamp () ;
1528
+ last_reply_timestamp = last_processing ;
1529
1529
waiting_for_ping_response = false;
1530
1530
}
1531
1531
}
@@ -1818,10 +1818,18 @@ WalSndComputeSleeptime(TimestampTz now)
1818
1818
1819
1819
/*
1820
1820
* Check whether there have been responses by the client within
1821
- * wal_sender_timeout and shutdown if not.
1821
+ * wal_sender_timeout and shutdown if not. Using last_processing as the
1822
+ * reference point avoids counting server-side stalls against the client.
1823
+ * However, a long server-side stall can make WalSndKeepaliveIfNecessary()
1824
+ * postdate last_processing by more than wal_sender_timeout. If that happens,
1825
+ * the client must reply almost immediately to avoid a timeout. This rarely
1826
+ * affects the default configuration, under which clients spontaneously send a
1827
+ * message every standby_message_timeout = wal_sender_timeout/6 = 10s. We
1828
+ * could eliminate that problem by recognizing timeout expiration at
1829
+ * wal_sender_timeout/2 after the keepalive.
1822
1830
*/
1823
1831
static void
1824
- WalSndCheckTimeOut (TimestampTz now )
1832
+ WalSndCheckTimeOut (void )
1825
1833
{
1826
1834
TimestampTz timeout ;
1827
1835
@@ -1832,7 +1840,7 @@ WalSndCheckTimeOut(TimestampTz now)
1832
1840
timeout = TimestampTzPlusMilliseconds (last_reply_timestamp ,
1833
1841
wal_sender_timeout );
1834
1842
1835
- if (wal_sender_timeout > 0 && now >= timeout )
1843
+ if (wal_sender_timeout > 0 && last_processing >= timeout )
1836
1844
{
1837
1845
/*
1838
1846
* Since typically expiration of replication timeout means
@@ -1863,8 +1871,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
1863
1871
*/
1864
1872
for (;;)
1865
1873
{
1866
- TimestampTz now ;
1867
-
1868
1874
/*
1869
1875
* Emergency bailout if postmaster has died. This is to avoid the
1870
1876
* necessity for manual cleanup of all postmaster children.
@@ -1942,13 +1948,11 @@ WalSndLoop(WalSndSendDataCallback send_data)
1942
1948
WalSndDone (send_data );
1943
1949
}
1944
1950
1945
- now = GetCurrentTimestamp ();
1946
-
1947
1951
/* Check for replication timeout. */
1948
- WalSndCheckTimeOut (now );
1952
+ WalSndCheckTimeOut ();
1949
1953
1950
1954
/* Send keepalive if the time has come */
1951
- WalSndKeepaliveIfNecessary (now );
1955
+ WalSndKeepaliveIfNecessary ();
1952
1956
1953
1957
/*
1954
1958
* We don't block if not caught up, unless there is unsent data
@@ -1966,7 +1970,11 @@ WalSndLoop(WalSndSendDataCallback send_data)
1966
1970
wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
1967
1971
WL_SOCKET_READABLE ;
1968
1972
1969
- sleeptime = WalSndComputeSleeptime (now );
1973
+ /*
1974
+ * Use fresh timestamp, not last_processed, to reduce the chance
1975
+ * of reaching wal_sender_timeout before sending a keepalive.
1976
+ */
1977
+ sleeptime = WalSndComputeSleeptime (GetCurrentTimestamp ());
1970
1978
1971
1979
if (pq_is_send_pending ())
1972
1980
wakeEvents |= WL_SOCKET_WRITEABLE ;
@@ -3037,7 +3045,7 @@ WalSndKeepalive(bool requestReply)
3037
3045
* Send keepalive message if too much time has elapsed.
3038
3046
*/
3039
3047
static void
3040
- WalSndKeepaliveIfNecessary (TimestampTz now )
3048
+ WalSndKeepaliveIfNecessary (void )
3041
3049
{
3042
3050
TimestampTz ping_time ;
3043
3051
@@ -3058,7 +3066,7 @@ WalSndKeepaliveIfNecessary(TimestampTz now)
3058
3066
*/
3059
3067
ping_time = TimestampTzPlusMilliseconds (last_reply_timestamp ,
3060
3068
wal_sender_timeout / 2 );
3061
- if (now >= ping_time )
3069
+ if (last_processing >= ping_time )
3062
3070
{
3063
3071
WalSndKeepalive (true);
3064
3072
waiting_for_ping_response = true;
0 commit comments