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"
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
644645XLogReaderInvalReadState (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