8000 Fix pg_xlogdump so that it handles cross-page XLP_FIRST_IS_CONTRECORD… · s-monk/postgres@314a25f · GitHub
[go: up one dir, main page]

Skip to content

Commit 314a25f

Browse files
committed
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
1 parent 5b79dd6 commit 314a25f

File tree

1 file changed

+64
-27
lines changed

1 file changed

+64
-27
lines changed

src/backend/access/transam/xlogreader.c

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -911,47 +911,84 @@ XLogRecPtr
911911
XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
912912
{
913913
XLogReaderState saved_state = *state;
914-
XLogRecPtr targetPagePtr;
915914
XLogRecPtr tmpRecPtr;
916-
int targetRecOff;
917915
XLogRecPtr found = InvalidXLogRecPtr;
918-
uint32 pageHeaderSize;
919916
XLogPageHeader header;
920917
XLogRecord *record;
921-
int readLen;
922918
char *errormsg;
923919

924920
Assert(!XLogRecPtrIsInvalid(RecPtr));
925921

926-
targetRecOff = RecPtr % XLOG_BLCKSZ;
922+
/*
923+
* skip over potential continuation data, keeping in mind that it may span
924+
* multiple pages
925+
*/
926+
tmpRecPtr = RecPtr;
927+
while (true)
928+
{
929+
XLogRecPtr targetPagePtr;
930+
int targetRecOff;
931+
uint32 pageHeaderSize;
932+
int readLen;
927933

928-
/* scroll back to page boundary */
929-
targetPagePtr = RecPtr - targetRecOff;
934+
/*
935+
* Compute targetRecOff. It should typically be equal or greater than
936+
* short page-header since a valid record can't start anywhere before
937+
* that, except when caller has explicitly specified the offset that
938+
* falls somewhere there or when we are skipping multi-page
939+
* continuation record. It doesn't matter though because
940+
* ReadPageInternal() is prepared to handle that and will read at least
941+
* short page-header worth of data
942+
*/
943+
targetRecOff = tmpRecPtr % XLOG_BLCKSZ;
930944

931-
/* Read the page containing the record */
932-
readLen = ReadPageInternal(state, targetPagePtr, targetRecOff);
933-
if (readLen < 0)
934-
goto err;
945+
/* scroll back to page boundary */
946+
targetPagePtr = tmpRecPtr - targetRecOff;
935947

936-
header = (XLogPageHeader) state->readBuf;
948+
/* Read the page containing the record */
949+
readLen = ReadPageInternal(state, targetPagePtr, targetRecOff);
950+
if (readLen < 0)
951+
goto err;
937952

938-
pageHeaderSize = XLogPageHeaderSize(header);
953+
header = (XLogPageHeader) state->readBuf;
939954

940-
/* make sure we have enough data for the page header */
941-
readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize);
942-
if (readLen < 0)
943-
goto err;
955+
pageHeaderSize = XLogPageHeaderSize(header);
944956

945-
/* skip over potential continuation data */
946-
if (header->xlp_info & XLP_FIRST_IS_CONTRECORD)
947-
{
948-
/* record headers are MAXALIGN'ed */
949-
tmpRecPtr = targetPagePtr + pageHeaderSize
950-
+ MAXALIGN(header->xlp_rem_len);
951-
}
952-
else
953-
{
954-
tmpRecPtr = targetPagePtr + pageHeaderSize;
957+
/* make sure we have enough data for the page header */
958+
readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize);
959+
if (readLen < 0)
960+
goto err;
961+
962+
/* skip over potential continuation data */
963+
if (header->xlp_info & XLP_FIRST_IS_CONTRECORD)
964+
{
965+
/*
966+
* If the length of the remaining continuation data is more than
967+
* what can fit in this page, the continuation record crosses over
968+
* this page. Read the next page and try again. xlp_rem_len in the
969+
* next page header will contain the remaining length of the
970+
* continuation data
971+
*
972+
* Note that record headers are MAXALIGN'ed
973+
*/
974+
if (MAXALIGN(header->xlp_rem_len) > (XLOG_BLCKSZ - pageHeaderSize))
975+
tmpRecPtr = targetPagePtr + XLOG_BLCKSZ;
976+
else
977+
{
978+
/*
979+
* The previous continuation record ends in this page. Set
980+
* tmpRecPtr to point to the first valid record
981+
*/
982+
tmpRecPtr = targetPagePtr + pageHeaderSize
983+
+ MAXALIGN(header->xlp_rem_len);
984+
break;
985+
}
986+
}
987+
else
988+
{
989+
tmpRecPtr = targetPagePtr + pageHeaderSize;
990+
break;
991+
}
955992
}
956993

957994
/*

0 commit comments

Comments
 (0)
0