Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0dc8ead

Browse filesBrowse files
committed
Refactor WAL file-reading code into WALRead()
XLogReader, walsender and pg_waldump all had their own routines to read data from WAL files to memory, with slightly different approaches according to the particular conditions of each environment. There's a lot of commonality, so we can refactor that into a single routine WALRead in XLogReader, and move the differences to a separate (simpler) callback that just opens the next WAL-segment. This results in a clearer (ahem) code flow. The error reporting needs are covered by filling in a new error-info struct, WALReadError, and it's the caller's responsibility to act on it. The backend has WALReadRaiseError() to do so. We no longer ever need to seek in this interface; switch to using pg_pread(). Author: Antonin Houska, with contributions from Álvaro Herrera Reviewed-by: Michaël Paquier, Kyotaro Horiguchi Discussion: https://postgr.es/m/14984.1554998742@spoje.net
1 parent 5883f5f commit 0dc8ead
Copy full SHA for 0dc8ead

File tree

Expand file treeCollapse file tree

6 files changed

+387
-433
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+387
-433
lines changed

‎src/backend/access/transam/xlogreader.c

Copy file name to clipboardExpand all lines: src/backend/access/transam/xlogreader.c
+100-6Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
*/
1818
#include "postgres.h"
1919

20+
#include <unistd.h>
21+
2022
#include "access/transam.h"
2123
#include "access/xlog_internal.h"
2224
#include "access/xlogreader.h"
@@ -27,6 +29,7 @@
2729

2830
#ifndef FRONTEND
2931
#include "miscadmin.h"
32+
#include "pgstat.h"
3033
#include "utils/memutils.h"
3134
#endif
3235

@@ -208,7 +211,6 @@ WALOpenSegmentInit(WALOpenSegment *seg, WALSegmentContext *segcxt,
208211
{
209212
seg->ws_file = -1;
210213
seg->ws_segno = 0;
211-
seg->ws_off = 0;
212214
seg->ws_tli = 0;
213215

214216
segcxt->ws_segsize = segsize;
@@ -295,8 +297,7 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
295297
* byte to cover the whole record header, or at least the part of it that
296298
* fits on the same page.
297299
*/
298-
readOff = ReadPageInternal(state,
299-
targetPagePtr,
300+
readOff = ReadPageInternal(state, targetPagePtr,
300301
Min(targetRecOff + SizeOfXLogRecord, XLOG_BLCKSZ));
301302
if (readOff < 0)
302303
goto err;
@@ -556,7 +557,7 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen)
556557

557558
/* check whether we have all the requested data already */
558559
if (targetSegNo == state->seg.ws_segno &&
559-
targetPageOff == state->seg.ws_off && reqLen <= state->readLen)
560+
targetPageOff == state->segoff && reqLen <= state->readLen)
560561
return state->readLen;
561562

562563
/*
@@ -627,7 +628,7 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen)
627628

628629
/* update read state information */
629630
state->seg.ws_segno = targetSegNo;
630-
state->seg.ws_off = targetPageOff;
631+
state->segoff = targetPageOff;
631632
state->readLen = readLen;
632633

633634
return readLen;
@@ -644,7 +645,7 @@ static void
644645
XLogReaderInvalReadState(XLogReaderState *state)
645646
{
646647
state->seg.ws_segno = 0;
647-
state->seg.ws_off = 0;
648+
state->segoff = 0;
648649
state->readLen = 0;
649650
}
650651

@@ -1015,6 +1016,99 @@ XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
10151016

10161017
#endif /* FRONTEND */
10171018

1019+
/*
1020+
* Read 'count' bytes into 'buf', starting at location 'startptr', from WAL
1021+
* fetched from timeline 'tli'.
1022+
*
1023+
* 'seg/segcxt' identify the last segment used. 'openSegment' is a callback
1024+
* to open the next segment, if necessary.
1025+
*
1026+
* Returns true if succeeded, false if an error occurs, in which case
1027+
* 'errinfo' receives error details.
1028+
*
1029+
* XXX probably this should be improved to suck data directly from the
1030+
* WAL buffers when possible.
1031+
*/
1032+
bool
1033+
WALRead(char *buf, XLogRecPtr startptr, Size count, TimeLineID tli,
1034+
WALOpenSegment *seg, WALSegmentContext *segcxt,
1035+
WALSegmentOpen openSegment, WALReadError *errinfo)
1036+
{
1037+
char *p;
1038+
XLogRecPtr recptr;
1039+
Size nbytes;
1040+
1041+
p = buf;
1042+
recptr = startptr;
1043+
nbytes = count;
1044+
1045+
while (nbytes > 0)
1046+
{
1047+
uint32 startoff;
1048+
int segbytes;
1049+
int readbytes;
1050+
1051+
startoff = XLogSegmentOffset(recptr, segcxt->ws_segsize);
1052+
1053+
/*
1054+
* If the data we want is not in a segment we have open, close what we
1055+
* have (if anything) and open the next one, using the caller's
1056+
* provided openSegment callback.
1057+
*/
1058+
if (seg->ws_file < 0 ||
1059+
!XLByteInSeg(recptr, seg->ws_segno, segcxt->ws_segsize) ||
1060+
tli != seg->ws_tli)
1061+
{
1062+
XLogSegNo nextSegNo;
1063+
1064+
if (seg->ws_file >= 0)
1065+
close(seg->ws_file);
1066+
1067+
XLByteToSeg(recptr, nextSegNo, segcxt->ws_segsize);
1068+
seg->ws_file = openSegment(nextSegNo, segcxt, &tli);
1069+
1070+
/* Update the current segment info. */
1071+
seg->ws_tli = tli;
1072+
seg->ws_segno = nextSegNo;
1073+
}
1074+
1075+
/* How many bytes are within this segment? */
1076+
if (nbytes > (segcxt->ws_segsize - startoff))
1077+
segbytes = segcxt->ws_segsize - startoff;
1078+
else
1079+
segbytes = nbytes;
1080+
1081+
#ifndef FRONTEND
1082+
pgstat_report_wait_start(WAIT_EVENT_WAL_READ);
1083+
#endif
1084+
1085+
/* Reset errno first; eases reporting non-errno-affecting errors */
1086+
errno = 0;
1087+
readbytes = pg_pread(seg->ws_file, p, segbytes, (off_t) startoff);
1088+
1089+
#ifndef FRONTEND
1090+
pgstat_report_wait_end();
1091+
#endif
1092+
1093+
if (readbytes <= 0)
1094+
{
1095+
errinfo->wre_errno = errno;
1096+
errinfo->wre_req = segbytes;
1097+
errinfo->wre_read = readbytes;
1098+
errinfo->wre_off = startoff;
1099+
errinfo->wre_seg = *seg;
1100+
return false;
1101+
}
1102+
1103+
/* Update state for read */
1104+
recptr += readbytes;
1105+
nbytes -= readbytes;
1106+
p += readbytes;
1107+
}
1108+
1109+
return true;
1110+
}
1111+
10181112
/* ----------------------------------------
10191113
* Functions for decoding the data and block references in a record.
10201114
* ----------------------------------------

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.