/* make sure we have enough WAL available */
flushptr = WalSndWaitForWal(targetPagePtr + reqLen);
- /* more than one block available */
- if (targetPagePtr + XLOG_BLCKSZ <= flushptr)
- count = XLOG_BLCKSZ;
- /* not enough WAL synced, that can happen during shutdown */
- else if (targetPagePtr + reqLen > flushptr)
+ /* fail if not (implies we are going to shut down) */
+ if (flushptr < targetPagePtr + reqLen)
return -1;
- /* part of the page available */
+
+ if (targetPagePtr + XLOG_BLCKSZ <= flushptr)
+ count = XLOG_BLCKSZ; /* more than one block available */
else
- count = flushptr - targetPagePtr;
+ count = flushptr - targetPagePtr; /* part of the page available */
/* now actually read the data, we know it's there */
XLogRead(cur_page, targetPagePtr, XLOG_BLCKSZ);
}
/*
- * Wait till WAL < loc is flushed to disk so it can be safely read.
+ * Wait till WAL < loc is flushed to disk so it can be safely sent to client.
+ *
+ * Returns end LSN of flushed WAL. Normally this will be >= loc, but
+ * if we detect a shutdown request (either from postmaster or client)
+ * we will return early, so caller must always check.
*/
static XLogRecPtr
WalSndWaitForWal(XLogRecPtr loc)
RecentFlushPtr = GetXLogReplayRecPtr(NULL);
/*
- * If postmaster asked us to stop, don't wait here anymore. This will
- * cause the xlogreader to return without reading a full record, which
- * is the fastest way to reach the mainloop which then can quit.
+ * If postmaster asked us to stop, don't wait anymore.
*
* It's important to do this check after the recomputation of
* RecentFlushPtr, so we can send all remaining data before shutting
WalSndCaughtUp = true;
/*
- * Try to flush pending output to the client. Also wait for the socket
- * becoming writable, if there's still pending output after an attempt
- * to flush. Otherwise we might just sit on output data while waiting
- * for new WAL being generated.
+ * Try to flush any pending output to the client.
*/
if (pq_flush_if_writable() != 0)
WalSndShutdown();
+ /*
+ * If we have received CopyDone from the client, sent CopyDone
+ * ourselves, and the output buffer is empty, it's time to exit
+ * streaming, so fail the current WAL fetch request.
+ */
+ if (streamingDoneReceiving && streamingDoneSending &&
+ !pq_is_send_pending())
+ break;
+
now = GetCurrentTimestamp();
/* die if timeout was reached */
/* Send keepalive if the time has come */
WalSndKeepaliveIfNecessary(now);
+ /*
+ * Sleep until something happens or we time out. Also wait for the
+ * socket becoming writable, if there's still pending output.
+ * Otherwise we might sit on sendable output data while waiting for
+ * new WAL to be generated. (But if we have nothing to send, we don't
+ * want to wake on socket-writable.)
+ */
sleeptime = WalSndComputeSleeptime(now);
wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
if (pq_is_send_pending())
wakeEvents |= WL_SOCKET_WRITEABLE;
- /* Sleep until something happens or we time out */
WaitLatchOrSocket(MyLatch, wakeEvents,
MyProcPort->sock, sleeptime,
WAIT_EVENT_WAL_SENDER_WAIT_WAL);
* ourselves, and the output buffer is empty, it's time to exit
* streaming.
*/
- if (!pq_is_send_pending() && streamingDoneSending && streamingDoneReceiving)
+ if (streamingDoneReceiving && streamingDoneSending &&
+ !pq_is_send_pending())
break;
/*