8000 Fix pg_xlogdump so that it handles cross-page XLP_FIRST_IS_CONTRECORD… · patchsoft/postgres@7dfb9b4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7dfb9b4

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 b09caec commit 7dfb9b4

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
@@ -844,46 +844,83 @@ XLogRecPtr
844844
XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
845845
{
846846
XLogReaderState saved_state = *state;
847-
XLogRecPtr targetPagePtr;
848847
XLogRecPtr tmpRecPtr;
849-
int targetRecOff;
850848
XLogRecPtr found = InvalidXLogRecPtr;
851-
uint32 pageHeaderSize;
852849
XLogPageHeader header;
853-
int readLen;
854850
char *errormsg;
855851

856852
Assert(!XLogRecPtrIsInvalid(RecPtr));
857853

858-
targetRecOff = RecPtr % XLOG_BLCKSZ;
854+
/*
855+
* skip over potential continuation data, keeping in mind that it may span
856+
* multiple pages
857+
*/
858+
tmpRecPtr = RecPtr;
859+
while (true)
860+
{
861+
XLogRecPtr targetPagePtr;
862+
int targetRecOff;
863+
uint32 pageHeaderSize;
864+
int readLen;
859865

860-
/* scroll back to page boundary */
861-
targetPagePtr = RecPtr - targetRecOff;
866+
/*
867+
* Compute targetRecOff. It should typically be equal or greater than
868+
* short page-header since a valid record can't start anywhere before
869+
* that, except when caller has explicitly specified the offset that
870+
* falls somewhere there or when we are skipping multi-page
871+
* continuation record. It doesn't matter though because
872+
* ReadPageInternal() is prepared to handle that and will read at least
873+
* short page-header worth of data
874+
*/
875+
targetRecOff = tmpRecPtr % XLOG_BLCKSZ;
862876

863-
/* Read the page containing the record */
864-
readLen = ReadPageInternal(state, targetPagePtr, targetRecOff);
865-
if (readLen < 0)
866-
goto err;
877+
/* scroll back to page boundary */
878+
targetPagePtr = tmpRecPtr - targetRecOff;
867879

868-
header = (XLogPageHeader) state->readBuf;
880+
/* Read the page containing the record */
881+
readLen = ReadPageInternal(state, targetPagePtr, targetRecOff);
882+
if (readLen < 0)
883+
goto err;
869884

870-
pageHeaderSize = XLogPageHeaderSize(header);
885+
header = (XLogPageHeader) state->readBuf;
871886

872-
/* make sure we have enough data for the page header */
873-
readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize);
874-
if (readLen < 0)
875-
goto err;
887+
pageHeaderSize = XLogPageHeaderSize(header);
876888

877-
/* skip over potential continuation data */
878-
if (header->xlp_info & XLP_FIRST_IS_CONTRECORD)
879-
{
880-
/* record headers are MAXALIGN'ed */
881-
tmpRecPtr = targetPagePtr + pageHeaderSize
882-
+ MAXALIGN(header->xlp_rem_len);
883-
}
884-
else
885-
{
886-
tmpRecPtr = targetPagePtr + pageHeaderSize;
889+
/* make sure we have enough data for the page header */
890+
readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize);
891+
if (readLen < 0)
892+
goto err;
893+
894+
/* skip over potential continuation data */
895+
if (header->xlp_info & XLP_FIRST_IS_CONTRECORD)
896+
{
897+
/*
898+
* If the length of the remaining continuation data is more than
899+
* what can fit in this page, the continuation record crosses over
900+
* this page. Read the next page and try again. xlp_rem_len in the
901+
* next page header will contain the remaining length of the
902+
* continuation data
903+
*
904+
* Note that record headers are MAXALIGN'ed
905+
*/
906+
if (MAXALIGN(header->xlp_rem_len) > (XLOG_BLCKSZ - pageHeaderSize))
907+
tmpRecPtr = targetPagePtr + XLOG_BLCKSZ;
908+
else
909+
{
910+
/*
911+
* The previous continuation record ends in this page. Set
912+
* tmpRecPtr to point to the first valid record
913+
*/
914+
tmpRecPtr = targetPagePtr + pageHeaderSize
915+
+ MAXALIGN(header->xlp_rem_len);
916+
break;
917+
}
918+
}
919+
else
920+
{
921+
tmpRecPtr = targetPagePtr + pageHeaderSize;
922+
break;
923+
}
887924
}
888925

889926
/*

0 commit comments

Comments
 (0)
0