I think I found what happened here.

One WAL record can be split between WAL files.

In XLogReadRecord, if last WAL record is incomplete, it try to get next WAL:
                /* Copy the first fragment of the record from the first page. */
                memcpy(state->readRecordBuf,
                           state->readBuf + RecPtr % XLOG_BLCKSZ, len);
                buffer = state->readRecordBuf + len;
                gotlen = len;

                do
                {
                        /* Calculate pointer to beginning of next page */
                        targetPagePtr += XLOG_BLCKSZ;

                        /* Wait for the next page to become available */
                        readOff = ReadPageInternal(state, targetPagePtr,
                                                                 Min(total_len 
- gotlen + SizeOfXLogShortPHD,
                                                                         
XLOG_BLCKSZ));

                        if (readOff < 0)
                                goto err;

but in my case next WAL not yet in archive (archive_timeout=0 in master)
and it clean cache:
err:

        /*
         * Invalidate the xlog page we've cached. We might read from a different
         * source after failure.
         */
        state->readSegNo = 0;
        state->readOff = 0;
        state->readLen = 0;

PG switch to streaming and last WAL (00000001000000000000002B for
example) still not replayed completely. We do not use streaming and it
switch back to archive:
LOG:  restored log file "00000001000000000000002B" from archive
...
DEBUG:  could not restore file "00000001000000000000002C" from archive: child 
process exited with exit code 1
DEBUG:  switched WAL source from archive to stream after failure
DEBUG:  switched WAL source from stream to archive after failure

Now it must reread first part of last WAL record from
00000001000000000000002B, but XLogFileReadAnyTLI is _always_ read
from the archive first, even if this file is already in pg_xlog:
                if (source == XLOG_FROM_ANY || source == XLOG_FROM_ARCHIVE)
                {
                        fd = XLogFileRead(segno, emode, tli,
                                                          XLOG_FROM_ARCHIVE, 
true);
                        if (fd != -1)
                        {
                                elog(DEBUG1, "got WAL segment from archive");
                                if (!expectedTLEs)
                                        expectedTLEs = tles;
                                return fd;
                        }
                }

                if (source == XLOG_FROM_ANY || source == XLOG_FROM_PG_XLOG)
                {
                        fd = XLogFileRead(segno, emode, tli,
                                                          XLOG_FROM_PG_XLOG, 
true);
                        if (fd != -1)
                        {
                                if (!expectedTLEs)
                                        expectedTLEs = tles;
                                return fd;
                        }
                }

Well, I think we'll be able to cache locally the last WAL file in 
restore_command
if needed :-)

-- 
Sergey Burladyan

Reply via email to