diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index ee8ab32878..67e722f757 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -2008,29 +2008,6 @@ SET ENABLE_SEQSCAN TO OFF; - - wal_sender_delay (integer) - - wal_sender_delay configuration parameter - - - - Specifies the delay between activity rounds for WAL sender processes. - In each round the WAL sender sends any WAL accumulated since the last - round to the standby server. It then sleeps for - wal_sender_delay milliseconds, and repeats. The sleep - is interrupted by transaction commit, so the effects of a committed - transaction are sent to standby servers as soon as the commit - happens, regardless of this setting. The default value is one second - (1s). - Note that on many systems, the effective resolution of sleep delays is - 10 milliseconds; setting wal_sender_delay to a value that - is not a multiple of 10 might have the same results as setting it to - the next higher multiple of 10. This parameter can only be set in the - postgresql.conf file or on the server command line. - - - wal_keep_segments (integer) diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 723d528330..0eadf6437e 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -75,7 +75,6 @@ bool am_cascading_walsender = false; /* Am I cascading WAL to another standby ? /* User-settable parameters for walsender */ int max_wal_senders = 0; /* the maximum number of concurrent walsenders */ -int WalSndDelay = 1000; /* max sleep time between some actions */ int replication_timeout = 60 * 1000; /* maximum time to send one * WAL data message */ @@ -475,7 +474,7 @@ ProcessRepliesIfAny(void) { unsigned char firstchar; int r; - int received = false; + bool received = false; for (;;) { @@ -709,6 +708,9 @@ WalSndLoop(void) /* Loop forever, unless we get an error */ for (;;) { + /* Clear any already-pending wakeups */ + ResetLatch(&MyWalSnd->latch); + /* * Emergency bailout if postmaster has died. This is to avoid the * necessity for manual cleanup of all postmaster children. @@ -727,94 +729,112 @@ WalSndLoop(void) /* Normal exit from the walsender is here */ if (walsender_shutdown_requested) { - /* Inform the standby that XLOG streaming was done */ + /* Inform the standby that XLOG streaming is done */ pq_puttextmessage('C', "COPY 0"); pq_flush(); proc_exit(0); } + /* Check for input from the client */ + ProcessRepliesIfAny(); + /* * If we don't have any pending data in the output buffer, try to send - * some more. + * some more. If there is some, we don't bother to call XLogSend + * again until we've flushed it ... but we'd better assume we are not + * caught up. */ if (!pq_is_send_pending()) - { XLogSend(output_message, &caughtup); + else + caughtup = false; - /* - * Even if we wrote all the WAL that was available when we started - * sending, more might have arrived while we were sending this - * batch. We had the latch set while sending, so we have not - * received any signals from that time. Let's arm the latch again, - * and after that check that we're still up-to-date. - */ - if (caughtup && !pq_is_send_pending()) - { - ResetLatch(&MyWalSnd->latch); - - XLogSend(output_message, &caughtup); - } - } - - /* Flush pending output to the client */ + /* Try to flush pending output to the client */ if (pq_flush_if_writable() != 0) break; - /* - * When SIGUSR2 arrives, we send any outstanding logs up to the - * shutdown checkpoint record (i.e., the latest record) and exit. - * This may be a normal termination at shutdown, or a promotion, - * the walsender is not sure which. - */ - if (walsender_ready_to_stop && !pq_is_send_pending()) + /* If nothing remains to be sent right now ... */ + if (caughtup && !pq_is_send_pending()) { - XLogSend(output_message, &caughtup); - ProcessRepliesIfAny(); - if (caughtup && !pq_is_send_pending()) - walsender_shutdown_requested = true; + /* + * If we're in catchup state, move to streaming. This is an + * important state change for users to know about, since before + * this point data loss might occur if the primary dies and we + * need to failover to the standby. The state change is also + * important for synchronous replication, since commits that + * started to wait at that point might wait for some time. + */ + if (MyWalSnd->state == WALSNDSTATE_CATCHUP) + { + ereport(DEBUG1, + (errmsg("standby \"%s\" has now caught up with primary", + application_name))); + WalSndSetState(WALSNDSTATE_STREAMING); + } + + /* + * When SIGUSR2 arrives, we send any outstanding logs up to the + * shutdown checkpoint record (i.e., the latest record) and exit. + * This may be a normal termination at shutdown, or a promotion, + * the walsender is not sure which. + */ + if (walsender_ready_to_stop) + { + /* ... let's just be real sure we're caught up ... */ + XLogSend(output_message, &caughtup); + if (caughtup && !pq_is_send_pending()) + { + walsender_shutdown_requested = true; + continue; /* don't want to wait more */ + } + } } - if ((caughtup || pq_is_send_pending()) && - !got_SIGHUP && - !walsender_shutdown_requested) + /* + * 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 || pq_is_send_pending()) { TimestampTz finish_time = 0; - long sleeptime; + long sleeptime = -1; int wakeEvents; - /* Reschedule replication timeout */ + wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | + WL_SOCKET_READABLE; + if (pq_is_send_pending()) + wakeEvents |= WL_SOCKET_WRITEABLE; + + /* Determine time until replication timeout */ if (replication_timeout > 0) { long secs; int usecs; finish_time = TimestampTzPlusMilliseconds(last_reply_timestamp, - replication_timeout); + replication_timeout); TimestampDifference(GetCurrentTimestamp(), finish_time, &secs, &usecs); sleeptime = secs * 1000 + usecs / 1000; - if (WalSndDelay < sleeptime) - sleeptime = WalSndDelay; - } - else - { - /* - * XXX: Without timeout, we don't really need the periodic - * wakeups anymore, WaitLatchOrSocket should reliably wake up - * as soon as something interesting happens. - */ - sleeptime = WalSndDelay; + /* Avoid Assert in WaitLatchOrSocket if timeout is past */ + if (sleeptime < 0) + sleeptime = 0; + wakeEvents |= WL_TIMEOUT; } - /* Sleep */ - wakeEvents = WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT; - if (pq_is_send_pending()) - wakeEvents |= WL_SOCKET_WRITEABLE; + /* Sleep until something happens or replication timeout */ WaitLatchOrSocket(&MyWalSnd->latch, wakeEvents, MyProcPort->sock, sleeptime); - /* Check for replication timeout */ + /* + * Check for replication timeout. Note we ignore the corner case + * possibility that the client replied just as we reached the + * timeout ... he's supposed to reply *before* that. + */ if (replication_timeout > 0 && GetCurrentTimestamp() >= finish_time) { @@ -828,24 +848,6 @@ WalSndLoop(void) break; } } - - /* - * If we're in catchup state, see if its time to move to streaming. - * This is an important state change for users, since before this - * point data loss might occur if the primary dies and we need to - * failover to the standby. The state change is also important for - * synchronous replication, since commits that started to wait at that - * point might wait for some time. - */ - if (MyWalSnd->state == WALSNDSTATE_CATCHUP && caughtup) - { - ereport(DEBUG1, - (errmsg("standby \"%s\" has now caught up with primary", - application_name))); - WalSndSetState(WALSNDSTATE_STREAMING); - } - - ProcessRepliesIfAny(); } /* diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 9f9f9c533f..6670997acd 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1997,17 +1997,6 @@ static struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, - { - {"wal_sender_delay", PGC_SIGHUP, REPLICATION_SENDING, - gettext_noop("WAL sender sleep time between WAL replications."), - NULL, - GUC_UNIT_MS - }, - &WalSndDelay, - 1000, 1, 10000, - NULL, NULL, NULL - }, - { {"replication_timeout", PGC_SIGHUP, REPLICATION_SENDING, gettext_noop("Sets the maximum time to wait for WAL replication."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 037316e727..c8bf0b33fc 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -200,7 +200,6 @@ #max_wal_senders = 0 # max number of walsender processes # (change requires restart) -#wal_sender_delay = 1s # walsender cycle time, 1-10000 milliseconds #wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables #replication_timeout = 60s # in milliseconds; 0 disables diff --git a/src/include/replication/walsender.h b/src/include/replication/walsender.h index cb8e70ef38..876d2aa61f 100644 --- a/src/include/replication/walsender.h +++ b/src/include/replication/walsender.h @@ -98,7 +98,6 @@ extern volatile sig_atomic_t walsender_shutdown_requested; extern volatile sig_atomic_t walsender_ready_to_stop; /* user-settable parameters */ -extern int WalSndDelay; extern int max_wal_senders; extern int replication_timeout;