mirror of
https://github.com/postgres/postgres.git
synced 2025-07-08 11:42:09 +03:00
Fix pg_xlogdump so that it handles cross-page XLP_FIRST_IS_CONTRECORD record.
Previously pg_xlogdump failed to dump the contents of the WAL file if the file starts with the continuation WAL record which spans more than one pages. Since pg_xlogdump assumed that the continuation record always fits on a page, it could not find the valid WAL record to start reading from in that case. This patch changes pg_xlogdump so that it can handle a continuation WAL record which crosses a page boundary and find the valid record to start reading from. Back-patch to 9.3 where pg_xlogdump was introduced. Author: Pavan Deolasee Reviewed-By: Michael Paquier and Craig Ringer Discussion: CABOikdPsPByMiG6J01DKq6om2+BNkxHTPkOyqHM2a4oYwGKsqQ@mail.gmail.com
This commit is contained in:
@ -866,46 +866,83 @@ XLogRecPtr
|
|||||||
XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
|
XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
|
||||||
{
|
{
|
||||||
XLogReaderState saved_state = *state;
|
XLogReaderState saved_state = *state;
|
||||||
XLogRecPtr targetPagePtr;
|
|
||||||
XLogRecPtr tmpRecPtr;
|
XLogRecPtr tmpRecPtr;
|
||||||
int targetRecOff;
|
|
||||||
XLogRecPtr found = InvalidXLogRecPtr;
|
XLogRecPtr found = InvalidXLogRecPtr;
|
||||||
uint32 pageHeaderSize;
|
|
||||||
XLogPageHeader header;
|
XLogPageHeader header;
|
||||||
int readLen;
|
|
||||||
char *errormsg;
|
char *errormsg;
|
||||||
|
|
||||||
Assert(!XLogRecPtrIsInvalid(RecPtr));
|
Assert(!XLogRecPtrIsInvalid(RecPtr));
|
||||||
|
|
||||||
targetRecOff = RecPtr % XLOG_BLCKSZ;
|
/*
|
||||||
|
* skip over potential continuation data, keeping in mind that it may span
|
||||||
/* scroll back to page boundary */
|
* multiple pages
|
||||||
targetPagePtr = RecPtr - targetRecOff;
|
*/
|
||||||
|
tmpRecPtr = RecPtr;
|
||||||
/* Read the page containing the record */
|
while (true)
|
||||||
readLen = ReadPageInternal(state, targetPagePtr, targetRecOff);
|
|
||||||
if (readLen < 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
header = (XLogPageHeader) state->readBuf;
|
|
||||||
|
|
||||||
pageHeaderSize = XLogPageHeaderSize(header);
|
|
||||||
|
|
||||||
/* make sure we have enough data for the page header */
|
|
||||||
readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize);
|
|
||||||
if (readLen < 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
/* skip over potential continuation data */
|
|
||||||
if (header->xlp_info & XLP_FIRST_IS_CONTRECORD)
|
|
||||||
{
|
{
|
||||||
/* record headers are MAXALIGN'ed */
|
XLogRecPtr targetPagePtr;
|
||||||
tmpRecPtr = targetPagePtr + pageHeaderSize
|
int targetRecOff;
|
||||||
+ MAXALIGN(header->xlp_rem_len);
|
uint32 pageHeaderSize;
|
||||||
}
|
int readLen;
|
||||||
else
|
|
||||||
{
|
/*
|
||||||
tmpRecPtr = targetPagePtr + pageHeaderSize;
|
* Compute targetRecOff. It should typically be equal or greater than
|
||||||
|
* short page-header since a valid record can't start anywhere before
|
||||||
|
* that, except when caller has explicitly specified the offset that
|
||||||
|
* falls somewhere there or when we are skipping multi-page
|
||||||
|
* continuation record. It doesn't matter though because
|
||||||
|
* ReadPageInternal() is prepared to handle that and will read at least
|
||||||
|
* short page-header worth of data
|
||||||
|
*/
|
||||||
|
targetRecOff = tmpRecPtr % XLOG_BLCKSZ;
|
||||||
|
|
||||||
|
/* scroll back to page boundary */
|
||||||
|
targetPagePtr = tmpRecPtr - targetRecOff;
|
||||||
|
|
||||||
|
/* Read the page containing the record */
|
||||||
|
readLen = ReadPageInternal(state, targetPagePtr, targetRecOff);
|
||||||
|
if (readLen < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
header = (XLogPageHeader) state->readBuf;
|
||||||
|
|
||||||
|
pageHeaderSize = XLogPageHeaderSize(header);
|
||||||
|
|
||||||
|
/* make sure we have enough data for the page header */
|
||||||
|
readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize);
|
||||||
|
if (readLen < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* skip over potential continuation data */
|
||||||
|
if (header->xlp_info & XLP_FIRST_IS_CONTRECORD)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the length of the remaining continuation data is more than
|
||||||
|
* what can fit in this page, the continuation record crosses over
|
||||||
|
* this page. Read the next page and try again. xlp_rem_len in the
|
||||||
|
* next page header will contain the remaining length of the
|
||||||
|
* continuation data
|
||||||
|
*
|
||||||
|
* Note that record headers are MAXALIGN'ed
|
||||||
|
*/
|
||||||
|
if (MAXALIGN(header->xlp_rem_len) > (XLOG_BLCKSZ - pageHeaderSize))
|
||||||
|
tmpRecPtr = targetPagePtr + XLOG_BLCKSZ;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The previous continuation record ends in this page. Set
|
||||||
|
* tmpRecPtr to point to the first valid record
|
||||||
|
*/
|
||||||
|
tmpRecPtr = targetPagePtr + pageHeaderSize
|
||||||
|
+ MAXALIGN(header->xlp_rem_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmpRecPtr = targetPagePtr + pageHeaderSize;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user