mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Send keepalives from walsender even when busy sending WAL.
If walsender doesn't hear from the client for the time specified by wal_sender_timeout, it will conclude the connection or client is dead, and disconnect. When half of wal_sender_timeout has elapsed, it sends a ping to the client, leaving it the remainig half of wal_sender_timeout to respond. However, it only checked if half of wal_sender_timeout had elapsed when it was about to sleep, so if it was busy sending WAL to the client for long enough, it would not send the ping request in time. Then the client would not know it needs to send a reply, and the walsender will disconnect even though the client is still alive. Fix that. Andres Freund, reviewed by Robert Haas, and some further changes by me. Backpatch to 9.3. Earlier versions relied on the client to send the keepalives on its own, and hence didn't have this problem.
This commit is contained in:
parent
3973034e6d
commit
dcd1131c83
@ -1068,30 +1068,14 @@ WalSndLoop(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't block if not caught up, unless there is unsent data
|
||||
* pending in which case we'd better block until the socket is
|
||||
* write-ready. This test is only needed for the case where XLogSend
|
||||
* loaded a subset of the available data but then pq_flush_if_writable
|
||||
* flushed it all --- we should immediately try to send more.
|
||||
* If half of wal_sender_timeout has lapsed without receiving any
|
||||
* reply from standby, send a keep-alive message requesting an
|
||||
* immediate reply.
|
||||
*/
|
||||
if ((caughtup && !streamingDoneSending) || pq_is_send_pending())
|
||||
if (wal_sender_timeout > 0 && !ping_sent)
|
||||
{
|
||||
TimestampTz timeout = 0;
|
||||
long sleeptime = 10000; /* 10 s */
|
||||
int wakeEvents;
|
||||
TimestampTz timeout;
|
||||
|
||||
wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
|
||||
WL_SOCKET_READABLE;
|
||||
|
||||
if (pq_is_send_pending())
|
||||
wakeEvents |= WL_SOCKET_WRITEABLE;
|
||||
else if (wal_sender_timeout > 0 && !ping_sent)
|
||||
{
|
||||
/*
|
||||
* If half of wal_sender_timeout has lapsed without receiving
|
||||
* any reply from standby, send a keep-alive message to
|
||||
* standby requesting an immediate reply.
|
||||
*/
|
||||
timeout = TimestampTzPlusMilliseconds(last_reply_timestamp,
|
||||
wal_sender_timeout / 2);
|
||||
if (GetCurrentTimestamp() >= timeout)
|
||||
@ -1104,13 +1088,32 @@ WalSndLoop(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine time until replication timeout */
|
||||
if (wal_sender_timeout > 0)
|
||||
/*
|
||||
* We don't block if not caught up, unless there is unsent data
|
||||
* pending in which case we'd better block until the socket is
|
||||
* write-ready. This test is only needed for the case where XLogSend
|
||||
* loaded a subset of the available data but then pq_flush_if_writable
|
||||
* flushed it all --- we should immediately try to send more.
|
||||
*/
|
||||
if ((caughtup && !streamingDoneSending) || pq_is_send_pending())
|
||||
{
|
||||
timeout = TimestampTzPlusMilliseconds(last_reply_timestamp,
|
||||
wal_sender_timeout);
|
||||
TimestampTz timeout;
|
||||
long sleeptime = 10000; /* 10 s */
|
||||
int wakeEvents;
|
||||
|
||||
wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
|
||||
WL_SOCKET_READABLE;
|
||||
|
||||
if (pq_is_send_pending())
|
||||
wakeEvents |= WL_SOCKET_WRITEABLE;
|
||||
|
||||
/*
|
||||
* If wal_sender_timeout is active, sleep in smaller increments
|
||||
* to not go over the timeout too much. XXX: Why not just sleep
|
||||
* until the timeout has elapsed?
|
||||
*/
|
||||
if (wal_sender_timeout > 0)
|
||||
sleeptime = 1 + (wal_sender_timeout / 10);
|
||||
}
|
||||
|
||||
/* Sleep until something happens or we time out */
|
||||
ImmediateInterruptOK = true;
|
||||
@ -1124,6 +1127,8 @@ WalSndLoop(void)
|
||||
* possibility that the client replied just as we reached the
|
||||
* timeout ... he's supposed to reply *before* that.
|
||||
*/
|
||||
timeout = TimestampTzPlusMilliseconds(last_reply_timestamp,
|
||||
wal_sender_timeout);
|
||||
if (wal_sender_timeout > 0 && GetCurrentTimestamp() >= timeout)
|
||||
{
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user