The code that reads the WAL from the archive, from pg_xlog, and from a
master server via walreceiver, is quite complicated. I'm talking about
the WaitForWALToBecomeAvailable() function in xlog.c. I got frustrated
with that while working on the "switching timeline over streaming
replication" patch.
Attached is a patch to refactor that logic into a more straightforward
state machine. It's always been a kind of a state machine, but it's been
hard to see, as the code wasn't explicitly written that way. Any objections?
The only user-visible effect is that this slightly changes the order
that recovery tries to read files from the archive, and pg_xlog, in the
presence of multiple timelines. At the moment, if recovery fails to find
a file on current timeline in the archive, it then tries to find it in
pg_xlog. If it's not found there either, it checks if the file on next
timeline exists in the archive, and then checks if exists in pg_xlog.
For example, if we're currently recovering timeline 2, and target
timeline is 4, and we're looking for WAL file A, the files are searched
for in this order:
1. File 00000004000000000000000A in archive
2. File 00000004000000000000000A in pg_xlog
3. File 00000003000000000000000A in archive
4. File 00000003000000000000000A in pg_xlog
5. File 00000002000000000000000A in archive
6. File 00000002000000000000000A in pg_xlog
With this patch, the order is:
1. File 00000004000000000000000A in archive
2. File 00000003000000000000000A in archive
3. File 00000002000000000000000A in archive
4. File 00000004000000000000000A in pg_xlog
5. File 00000003000000000000000A in pg_xlog
6. File 00000002000000000000000A in pg_xlog
This change should have no effect in normal restore scenarios. It'd only
make a difference if some files in the middle of the sequence of WAL
files are missing from the archive, but have been copied to pg_xlog
manually, and only if that file contains a timeline switch. Even then, I
think I like the new order better; it's easier to explain if nothing else.
- Heikki
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 512,523 **** static XLogwrtResult LogwrtResult = {0, 0};
/*
* Codes indicating where we got a WAL file from during recovery, or where
! * to attempt to get one. These are chosen so that they can be OR'd together
! * in a bitmask state variable.
*/
! #define XLOG_FROM_ARCHIVE (1<<0) /* Restored using restore_command */
! #define XLOG_FROM_PG_XLOG (1<<1) /* Existing file in pg_xlog */
! #define XLOG_FROM_STREAM (1<<2) /* Streamed from master */
/*
* openLogFile is -1 or a kernel FD for an open log file segment.
--- 512,529 ----
/*
* Codes indicating where we got a WAL file from during recovery, or where
! * to attempt to get one.
*/
! typedef enum
! {
! XLOG_FROM_ANY = 0, /* request to read WAL from any source */
! XLOG_FROM_ARCHIVE, /* restored using restore_command */
! XLOG_FROM_PG_XLOG, /* existing file in pg_xlog */
! XLOG_FROM_STREAM, /* streamed from master */
! } XLogSource;
!
! /* human-readable names for XLogSources, for debugging output */
! static const char *xlogSourceNames[] = { "any", "archive", "pg_xlog", "stream" };
/*
* openLogFile is -1 or a kernel FD for an open log file segment.
***************
*** 542,563 **** static XLogSegNo readSegNo = 0;
static uint32 readOff = 0;
static uint32 readLen = 0;
static bool readFileHeaderValidated = false;
! static int readSource = 0; /* XLOG_FROM_* code */
/*
! * Keeps track of which sources we've tried to read the current WAL
! * record from and failed.
*/
! static int failedSources = 0; /* OR of XLOG_FROM_* codes */
/*
* These variables track when we last obtained some WAL data to process,
* and where we got it from. (XLogReceiptSource is initially the same as
* readSource, but readSource gets reset to zero when we don't have data
! * to process right now.)
*/
static TimestampTz XLogReceiptTime = 0;
! static int XLogReceiptSource = 0; /* XLOG_FROM_* code */
/* Buffer for currently read page (XLOG_BLCKSZ bytes) */
static char *readBuf = NULL;
--- 548,575 ----
static uint32 readOff = 0;
static uint32 readLen = 0;
static bool readFileHeaderValidated = false;
! static XLogSource readSource = 0; /* XLOG_FROM_* code */
/*
! * Keeps track of which source we're currently reading from. This is
! * different from readSource in that this is always set, even when we don't
! * currently have a WAL file open. If lastSourceFailed is set, our last
! * attempt to read from currentSource failed, and we should try another source
! * next.
*/
! static XLogSource currentSource = 0; /* XLOG_FROM_* code */
! static bool lastSourceFailed = false;
/*
* These variables track when we last obtained some WAL data to process,
* and where we got it from. (XLogReceiptSource is initially the same as
* readSource, but readSource gets reset to zero when we don't have data
! * to process right now. It is also different from currentSource, which
! * also changes when we try to read from a source and fail, while
! * XLogReceiptSource tracks where we last successfully read some WAL.)
*/
static TimestampTz XLogReceiptTime = 0;
! static XLogSource XLogReceiptSource = 0; /* XLOG_FROM_* code */
/* Buffer for currently read page (XLOG_BLCKSZ bytes) */
static char *readBuf = NULL;
***************
*** 630,636 **** static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
bool use_lock);
static int XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
int source, bool notexistOk);
! static int XLogFileReadAnyTLI(XLogSegNo segno, int emode, int sources);
static bool XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
bool randAccess);
static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
--- 642,648 ----
bool use_lock);
static int XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
int source, bool notexistOk);
! static int XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
static bool XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
bool randAccess);
static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
***************
*** 2576,2582 **** XLogFileOpen(XLogSegNo segno)
/*
* Open a logfile segment for reading (during recovery).
*
! * If source = XLOG_FROM_ARCHIVE, the segment is retrieved from archive.
* Otherwise, it's assumed to be already available in pg_xlog.
*/
static int
--- 2588,2594 ----
/*
* Open a logfile segment for reading (during recovery).
*
! * If source == XLOG_FROM_ARCHIVE, the segment is retrieved from archive.
* Otherwise, it's assumed to be already available in pg_xlog.
*/
static int
***************
*** 2722,2728 **** XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
* This version searches for the segment with any TLI listed in expectedTLIs.
*/
static int
! XLogFileReadAnyTLI(XLogSegNo segno, int emode, int sources)
{
char path[MAXPGPATH];
ListCell *cell;
--- 2734,2740 ----
* This version searches for the segment with any TLI listed in expectedTLIs.
*/
static int
! XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source)
{
char path[MAXPGPATH];
ListCell *cell;
***************
*** 2745,2751 **** XLogFileReadAnyTLI(XLogSegNo segno, int emode, int sources)
if (tli < curFileTLI)
break; /* don't bother looking at too-old TLIs */
! if (sources & XLOG_FROM_ARCHIVE)
{
fd = XLogFileRead(segno, emode, tli, XLOG_FROM_ARCHIVE, true);
if (fd != -1)
--- 2757,2763 ----
if (tli < curFileTLI)
break; /* don't bother looking at too-old TLIs */
! if (source == XLOG_FROM_ANY || source == XLOG_FROM_ARCHIVE)
{
fd = XLogFileRead(segno, emode, tli, XLOG_FROM_ARCHIVE, true);
if (fd != -1)
***************
*** 2755,2761 **** XLogFileReadAnyTLI(XLogSegNo segno, int emode, int sources)
}
}
! if (sources & XLOG_FROM_PG_XLOG)
{
fd = XLogFileRead(segno, emode, tli, XLOG_FROM_PG_XLOG, true);
if (fd != -1)
--- 2767,2773 ----
}
}
! if (source == XLOG_FROM_ANY || source == XLOG_FROM_PG_XLOG)
{
fd = XLogFileRead(segno, emode, tli, XLOG_FROM_PG_XLOG, true);
if (fd != -1)
***************
*** 3357,3363 **** ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
}
/* This is the first try to read this page. */
! failedSources = 0;
retry:
/* Read the page containing the record */
if (!XLogPageRead(RecPtr, emode, fetching_ckpt, randAccess))
--- 3369,3375 ----
}
/* This is the first try to read this page. */
! lastSourceFailed = false;
retry:
/* Read the page containing the record */
if (!XLogPageRead(RecPtr, emode, fetching_ckpt, randAccess))
***************
*** 3570,3576 **** retry:
return record;
next_record_is_invalid:
! failedSources |= readSource;
if (readFile >= 0)
{
--- 3582,3588 ----
return record;
next_record_is_invalid:
! lastSourceFailed = true;
if (readFile >= 0)
{
***************
*** 9266,9272 **** CancelBackup(void)
* In standby mode, if after a successful return of XLogPageRead() the
* caller finds the record it's interested in to be broken, it should
* ereport the error with the level determined by
! * emode_for_corrupt_record(), and then set "failedSources |= readSource"
* and call XLogPageRead() again with the same arguments. This lets
* XLogPageRead() to try fetching the record from another source, or to
* sleep and retry.
--- 9278,9284 ----
* In standby mode, if after a successful return of XLogPageRead() the
* caller finds the record it's interested in to be broken, it should
* ereport the error with the level determined by
! * emode_for_corrupt_record(), and then set lastSourceFailed
* and call XLogPageRead() again with the same arguments. This lets
* XLogPageRead() to try fetching the record from another source, or to
* sleep and retry.
***************
*** 9284,9290 **** XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
targetRecOff = (*RecPtr) % XLOG_BLCKSZ;
/* Fast exit if we have read the record in the current buffer already */
! if (failedSources == 0 && targetSegNo == readSegNo &&
targetPageOff == readOff && targetRecOff < readLen)
return true;
--- 9296,9302 ----
targetRecOff = (*RecPtr) % XLOG_BLCKSZ;
/* Fast exit if we have read the record in the current buffer already */
! if (!lastSourceFailed && targetSegNo == readSegNo &&
targetPageOff == readOff && targetRecOff < readLen)
return true;
***************
*** 9331,9347 **** retry:
/* In archive or crash recovery. */
if (readFile < 0)
{
! int sources;
/* Reset curFileTLI if random fetch. */
if (randAccess)
curFileTLI = 0;
- sources = XLOG_FROM_PG_XLOG;
if (InArchiveRecovery)
! sources |= XLOG_FROM_ARCHIVE;
! readFile = XLogFileReadAnyTLI(readSegNo, emode, sources);
if (readFile < 0)
return false;
}
--- 9343,9360 ----
/* In archive or crash recovery. */
if (readFile < 0)
{
! int source;
/* Reset curFileTLI if random fetch. */
if (randAccess)
curFileTLI = 0;
if (InArchiveRecovery)
! source = XLOG_FROM_ANY;
! else
! source = XLOG_FROM_PG_XLOG;
! readFile = XLogFileReadAnyTLI(readSegNo, emode, source);
if (readFile < 0)
return false;
}
***************
*** 9430,9436 **** retry:
return true;
next_record_is_invalid:
! failedSources |= readSource;
if (readFile >= 0)
close(readFile);
--- 9443,9449 ----
return true;
next_record_is_invalid:
! lastSourceFailed = true;
if (readFile >= 0)
close(readFile);
***************
*** 9470,9654 **** WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
bool fetching_ckpt)
{
static pg_time_t last_fail_time = 0;
for (;;)
{
! if (WalRcvInProgress())
{
- bool havedata;
! /*
! * If we find an invalid record in the WAL streamed from master,
! * something is seriously wrong. There's little chance that the
! * problem will just go away, but PANIC is not good for
! * availability either, especially in hot standby mode.
! * Disconnect, and retry from archive/pg_xlog again. The WAL in
! * the archive should be identical to what was streamed, so it's
! * unlikely that it helps, but one can hope...
! */
! if (failedSources & XLOG_FROM_STREAM)
{
! ShutdownWalRcv();
! continue;
! }
! /*
! * Walreceiver is active, so see if new data has arrived.
! *
! * We only advance XLogReceiptTime when we obtain fresh WAL from
! * walreceiver and observe that we had already processed
! * everything before the most recent "chunk" that it flushed to
! * disk. In steady state where we are keeping up with the
! * incoming data, XLogReceiptTime will be updated on each cycle.
! * When we are behind, XLogReceiptTime will not advance, so the
! * grace time allotted to conflicting queries will decrease.
! */
! if (XLByteLT(RecPtr, receivedUpto))
! havedata = true;
! else
! {
! XLogRecPtr latestChunkStart;
! receivedUpto = GetWalRcvWriteRecPtr(&latestChunkStart);
! if (XLByteLT(RecPtr, receivedUpto))
! {
! havedata = true;
! if (!XLByteLT(RecPtr, latestChunkStart))
{
! XLogReceiptTime = GetCurrentTimestamp();
! SetCurrentChunkStartTime(XLogReceiptTime);
}
! }
! else
! havedata = false;
! }
! if (havedata)
! {
! /*
! * Great, streamed far enough. Open the file if it's not open
! * already. Use XLOG_FROM_STREAM so that source info is set
! * correctly and XLogReceiptTime isn't changed.
! */
! if (readFile < 0)
! {
! readFile = XLogFileRead(readSegNo, PANIC,
! recoveryTargetTLI,
! XLOG_FROM_STREAM, false);
! Assert(readFile >= 0);
! }
! else
! {
! /* just make sure source info is correct... */
! readSource = XLOG_FROM_STREAM;
! XLogReceiptSource = XLOG_FROM_STREAM;
! }
! break;
! }
! /*
! * Data not here yet, so check for trigger then sleep for five
! * seconds like in the WAL file polling case below.
! */
! if (CheckForStandbyTrigger())
! return false;
! /*
! * Wait for more WAL to arrive, or timeout to be reached
! */
! WaitLatch(&XLogCtl->recoveryWakeupLatch,
! WL_LATCH_SET | WL_TIMEOUT,
! 5000L);
! ResetLatch(&XLogCtl->recoveryWakeupLatch);
}
! else
{
/*
! * WAL receiver is not active. Poll the archive.
*/
! int sources;
! pg_time_t now;
! if (readFile >= 0)
! {
! close(readFile);
! readFile = -1;
! }
! /* Reset curFileTLI if random fetch. */
! if (randAccess)
! curFileTLI = 0;
- /*
- * Try to restore the file from archive, or read an existing file
- * from pg_xlog.
- */
- sources = XLOG_FROM_ARCHIVE | XLOG_FROM_PG_XLOG;
- if (!(sources & ~failedSources))
- {
/*
! * We've exhausted all options for retrieving the file. Retry.
*/
! failedSources = 0;
/*
! * Before we sleep, re-scan for possible new timelines if we
! * were requested to recover to the latest timeline.
*/
! if (recoveryTargetIsLatest)
! {
! if (rescanLatestTimeLine())
! continue;
! }
/*
! * If it hasn't been long since last attempt, sleep to avoid
! * busy-waiting.
*/
! now = (pg_time_t) time(NULL);
! if ((now - last_fail_time) < 5)
{
! pg_usleep(1000000L * (5 - (now - last_fail_time)));
! now = (pg_time_t) time(NULL);
}
- last_fail_time = now;
/*
! * If primary_conninfo is set, launch walreceiver to try to
! * stream the missing WAL, before retrying to restore from
! * archive/pg_xlog.
*
! * If fetching_ckpt is TRUE, RecPtr points to the initial
! * checkpoint location. In that case, we use RedoStartLSN as
! * the streaming start position instead of RecPtr, so that
! * when we later jump backwards to start redo at RedoStartLSN,
! * we will have the logs streamed already.
*/
! if (PrimaryConnInfo)
{
! XLogRecPtr ptr = fetching_ckpt ? RedoStartLSN : RecPtr;
! RequestXLogStreaming(ptr, PrimaryConnInfo);
! continue;
}
- }
- /* Don't try to read from a source that just failed */
- sources &= ~failedSources;
- readFile = XLogFileReadAnyTLI(readSegNo, DEBUG2, sources);
- if (readFile >= 0)
- break;
! /*
! * Nope, not found in archive and/or pg_xlog.
! */
! failedSources |= sources;
! /*
! * Check to see if the trigger file exists. Note that we do this
! * only after failure, so when you create the trigger file, we
! * still finish replaying as much as we can from archive and
! * pg_xlog before failover.
! */
! if (CheckForStandbyTrigger())
! return false;
}
/*
--- 9483,9771 ----
bool fetching_ckpt)
{
static pg_time_t last_fail_time = 0;
+ pg_time_t now;
+
+ /*-------
+ * Standby mode is implemented by a state machine:
+ *
+ * 1. Read from archive (XLOG_FROM_ARCHIVE)
+ * 2. Read from pg_xlog (XLOG_FROM_PG_XLOG)
+ * 3. Check trigger file
+ * 4. Read from primary server via walreceiver (XLOG_FROM_STREAM)
+ * 5. Rescan timelines
+ * 6. Sleep 5 seconds, and loop back to 1.
+ *
+ * Failure to read from the current source advances the state machine to
+ * the next state. In addition, successfully reading a file from pg_xlog
+ * moves the state machine from state 2 back to state 1 (we always prefer
+ * files in the archive over files in pg_xlog).
+ *
+ * 'currentSource' indicates the current state. There is no currentSource
+ * value for "check trigger", "rescan timelines", and "sleep" states,
+ * those actions are taken when reading from the previous source fails, as
+ * part of advancing to the next state.
+ *-------
+ */
+ if (currentSource == 0)
+ currentSource = XLOG_FROM_ARCHIVE;
for (;;)
{
! int oldSource = currentSource;
!
! /*
! * First check if we failed to read from the current source, and
! * advance the state machine if so. The failure to read might've
! * happened outside this function, e.g when a CRC check fails on a
! * record, or within this loop.
! */
! if (lastSourceFailed)
{
! switch (currentSource)
{
! case XLOG_FROM_ARCHIVE:
! currentSource = XLOG_FROM_PG_XLOG;
! break;
! case XLOG_FROM_PG_XLOG:
! /*
! * Check to see if the trigger file exists. Note that we do
! * this only after failure, so when you create the trigger
! * file, we still finish replaying as much as we can from
! * archive and pg_xlog before failover.
! */
! if (CheckForStandbyTrigger())
! return false;
! /*
! * If primary_conninfo is set, launch walreceiver to try to
! * stream the missing WAL.
! *
! * If fetching_ckpt is TRUE, RecPtr points to the initial
! * checkpoint location. In that case, we use RedoStartLSN as
! * the streaming start position instead of RecPtr, so that
! * when we later jump backwards to start redo at
! * RedoStartLSN, we will have the logs streamed already.
! */
! if (PrimaryConnInfo)
{
! XLogRecPtr ptr = fetching_ckpt ? RedoStartLSN : RecPtr;
!
! RequestXLogStreaming(ptr, PrimaryConnInfo);
}
! /*
! * Move to XLOG_FROM_STREAM state in either case. We'll get
! * immediate failure if we didn't launch walreceiver, and
! * move on to the next state.
! */
! currentSource = XLOG_FROM_STREAM;
! break;
! case XLOG_FROM_STREAM:
! /*
! * Failure while streaming. Most likely, we got here because
! * streaming replication was terminated, or promotion was
! * triggered. But we also get here if we find an invalid
! * record in the WAL streamed from master, in which case
! * something is seriously wrong. There's little chance that
! * the problem will just go away, but PANIC is not good for
! * availability either, especially in hot standby mode. So,
! * we treat that the same as disconnection, and retry from
! * archive/pg_xlog again. The WAL in the archive should be
! * identical to what was streamed, so it's unlikely that it
! * helps, but one can hope...
! */
! /*
! * Before we leave XLOG_FROM_STREAM state, make sure that
! * walreceiver is not running, so that it won't overwrite
! * any WAL that we restore from archive.
! */
! if (WalRcvInProgress())
! ShutdownWalRcv();
! /*
! * Before we sleep, re-scan for possible new timelines if
! * we were requested to recover to the latest timeline.
! */
! if (recoveryTargetIsLatest)
! {
! if (rescanLatestTimeLine())
! {
! currentSource = XLOG_FROM_ARCHIVE;
! break;
! }
! }
!
! /*
! * XLOG_FROM_STREAM is the last state in our state machine,
! * so we've exhausted all the options for obtaining the
! * requested WAL. We're going to loop back and retry from
! * the archive next, but if it hasn't been long since last
! * attempt, sleep 5 seconds to avoid busy-waiting.
! */
! now = (pg_time_t) time(NULL);
! if ((now - last_fail_time) < 5)
! {
! pg_usleep(1000000L * (5 - (now - last_fail_time)));
! now = (pg_time_t) time(NULL);
! }
! last_fail_time = now;
! currentSource = XLOG_FROM_ARCHIVE;
! break;
!
! default:
! elog(ERROR, "unexpected WAL source %d", currentSource);
! }
}
! else if (currentSource == XLOG_FROM_PG_XLOG)
{
/*
! * We just successfully read a file in pg_xlog. We prefer files
! * in the archive over ones in pg_xlog, so try the next file
! * again from the archive first.
*/
! currentSource = XLOG_FROM_ARCHIVE;
! }
! if (currentSource != oldSource)
! elog(LOG, "switched WAL source from %s to %s after %s",
! xlogSourceNames[oldSource], xlogSourceNames[currentSource],
! lastSourceFailed ? "failure" : "success");
!
! /*
! * We've now handled possible failure. Try to read from the chosen
! * source.
! */
! lastSourceFailed = false;
!
! switch (currentSource)
! {
! case XLOG_FROM_ARCHIVE:
! case XLOG_FROM_PG_XLOG:
! /* Close any old file we might have open. */
! if (readFile >= 0)
! {
! close(readFile);
! readFile = -1;
! }
! /* Reset curFileTLI if random fetch. */
! if (randAccess)
! curFileTLI = 0;
/*
! * Try to restore the file from archive, or read an existing
! * file from pg_xlog.
*/
! readFile = XLogFileReadAnyTLI(readSegNo, DEBUG2, currentSource);
! if (readFile >= 0)
! return true; /* success! */
/*
! * Nope, not found in archive or pg_xlog.
*/
! lastSourceFailed = true;
! break;
!
! case XLOG_FROM_STREAM:
! {
! bool havedata;
/*
! * Check if WAL receiver is still active.
*/
! if (!WalRcvInProgress())
{
! lastSourceFailed = true;
! break;
}
/*
! * Walreceiver is active, so see if new data has arrived.
*
! * We only advance XLogReceiptTime when we obtain fresh WAL
! * from walreceiver and observe that we had already processed
! * everything before the most recent "chunk" that it flushed to
! * disk. In steady state where we are keeping up with the
! * incoming data, XLogReceiptTime will be updated on each cycle.
! * When we are behind, XLogReceiptTime will not advance, so the
! * grace time allotted to conflicting queries will decrease.
*/
! if (XLByteLT(RecPtr, receivedUpto))
! havedata = true;
! else
{
! XLogRecPtr latestChunkStart;
! receivedUpto = GetWalRcvWriteRecPtr(&latestChunkStart);
! if (XLByteLT(RecPtr, receivedUpto))
! {
! havedata = true;
! if (!XLByteLT(RecPtr, latestChunkStart))
! {
! XLogReceiptTime = GetCurrentTimestamp();
! SetCurrentChunkStartTime(XLogReceiptTime);
! }
! }
! else
! havedata = false;
! }
! if (havedata)
! {
! /*
! * Great, streamed far enough. Open the file if it's not
! * open already. Use XLOG_FROM_STREAM so that source info
! * is set correctly and XLogReceiptTime isn't changed.
! */
! if (readFile < 0)
! {
! readFile = XLogFileRead(readSegNo, PANIC,
! recoveryTargetTLI,
! XLOG_FROM_STREAM, false);
! Assert(readFile >= 0);
! }
! else
! {
! /* just make sure source info is correct... */
! readSource = XLOG_FROM_STREAM;
! XLogReceiptSource = XLOG_FROM_STREAM;
! return true;
! }
! break;
}
! /*
! * Data not here yet. Check for trigger, then wait for
! * walreceiver to wake us up when new WAL arrives.
! */
! if (CheckForStandbyTrigger())
! {
! /*
! * Note that we don't "return false" immediately here.
! * After being triggered, we still want to replay all the
! * WAL that was already streamed. It's in pg_xlog now, so
! * we just treat this as a failure, and the state machine
! * will move on to replay the streamed WAL from pg_xlog,
! * and then recheck the trigger and exit replay.
! */
! lastSourceFailed = true;
! break;
! }
! /*
! * Wait for more WAL to arrive. Time out after 5 seconds, like
! * when polling the archive, to react to a trigger file
! * promptly.
! */
! WaitLatch(&XLogCtl->recoveryWakeupLatch,
! WL_LATCH_SET | WL_TIMEOUT,
! 5000L);
! ResetLatch(&XLogCtl->recoveryWakeupLatch);
! break;
! }
!
! default:
! elog(ERROR, "unexpected WAL source %d", currentSource);
}
/*
***************
*** 9658,9664 **** WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
HandleStartupProcInterrupts();
}
! return true;
}
/*
--- 9775,9781 ----
HandleStartupProcInterrupts();
}
! return false; /* not reached */
}
/*
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers