Attachment.
--
Álvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 006c6298c9..e7a504c304 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -298,8 +298,7 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
* byte to cover the whole record header, or at least the part of it that
* fits on the same page.
*/
- readOff = ReadPageInternal(state,
- targetPagePtr,
+ readOff = ReadPageInternal(state, targetPagePtr,
Min(targetRecOff + SizeOfXLogRecord, XLOG_BLCKSZ));
if (readOff < 0)
goto err;
@@ -1019,23 +1018,22 @@ out:
#endif /* FRONTEND */
/*
- * Read 'count' bytes from WAL fetched from timeline 'tli' into 'buf',
- * starting at location 'startptr'. 'seg' is the last segment used,
- * 'openSegment' is a callback to open the next segment and 'segcxt' is
- * additional segment info that does not fit into 'seg'.
+ * Read 'count' bytes into 'buf', starting at location 'startptr', from WAL
+ * fetched from timeline 'tli'.
*
- * 'errinfo' should point to XLogReadError structure which will receive error
- * details in case the read fails.
+ * 'seg/segcxt' identify the last segment used. 'openSegment' is a callback
+ * to open the next segment, if necessary.
*
- * Returns true if succeeded, false if failed.
+ * Returns true if succeeded, false if an error occurs, in which case
+ * 'errinfo' receives error details.
*
* XXX probably this should be improved to suck data directly from the
* WAL buffers when possible.
*/
bool
-XLogRead(char *buf, XLogRecPtr startptr, Size count, TimeLineID tli,
- WALOpenSegment *seg, WALSegmentContext *segcxt,
- WALSegmentOpen openSegment, WALReadError *errinfo)
+WALRead(char *buf, XLogRecPtr startptr, Size count, TimeLineID tli,
+ WALOpenSegment *seg, WALSegmentContext *segcxt,
+ WALSegmentOpen openSegment, WALReadError *errinfo)
{
char *p;
XLogRecPtr recptr;
@@ -1066,7 +1064,7 @@ XLogRead(char *buf, XLogRecPtr startptr, Size count, TimeLineID tli,
XLByteToSeg(recptr, nextSegNo, segcxt->ws_segsize);
/* Open the next segment in the caller's way. */
- openSegment(nextSegNo, segcxt, &tli, &seg->ws_file);
+ seg->ws_file = openSegment(nextSegNo, segcxt, &tli);
/* Update the current segment info. */
seg->ws_tli = tli;
@@ -1085,11 +1083,11 @@ XLogRead(char *buf, XLogRecPtr startptr, Size count, TimeLineID tli,
if (lseek(seg->ws_file, (off_t) startoff, SEEK_SET) < 0)
{
- errinfo->xlr_seek = true;
+ errinfo->xlr_oper = WRE_OPER_SEEK;
errinfo->xlr_errno = errno;
errinfo->xlr_req = 0;
errinfo->xlr_read = 0;
- errinfo->xlr_seg = seg;
+ errinfo->xlr_seg = *seg;
return false;
}
}
@@ -1119,11 +1117,11 @@ XLogRead(char *buf, XLogRecPtr startptr, Size count, TimeLineID tli,
if (readbytes <= 0)
{
- errinfo->xlr_seek = false;
+ errinfo->xlr_oper = WRE_OPER_OPEN;
errinfo->xlr_errno = errno;
errinfo->xlr_req = segbytes;
errinfo->xlr_read = readbytes;
- errinfo->xlr_seg = seg;
+ errinfo->xlr_seg = *seg;
return false;
}
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 98118f484e..4047be5a0b 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -931,8 +931,8 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
* as 'count', read the whole page anyway. It's guaranteed to be
* zero-padded up to the page boundary if it's incomplete.
*/
- if (!XLogRead(cur_page, targetPagePtr, XLOG_BLCKSZ, tli, &state->seg,
- &state->segcxt, wal_segment_open, &errinfo))
+ if (!WALRead(cur_page, targetPagePtr, XLOG_BLCKSZ, tli, &state->seg,
+ &state->segcxt, wal_segment_open, &errinfo))
WALReadRaiseError(&errinfo);
/* number of valid bytes in the buffer */
@@ -941,36 +941,41 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
/*
* Backend-specific convenience code to handle read errors encountered by
- * XLogRead().
+ * WALRead().
*/
void
WALReadRaiseError(WALReadError *errinfo)
{
- WALOpenSegment *seg = errinfo->xlr_seg;
+ WALOpenSegment *seg = &errinfo->xlr_seg;
char *fname = XLogFileNameP(seg->ws_tli, seg->ws_segno);
- if (errinfo->xlr_seek)
+ switch (errinfo->xlr_oper)
{
- errno = errinfo->xlr_errno;
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not seek in log segment %s to offset %u: %m",
- fname, seg->ws_off)));
- }
- else if (errinfo->xlr_read < 0)
- {
- errno = errinfo->xlr_errno;
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read from log segment %s, offset %u, length %zu: %m",
- fname, seg->ws_off, (Size) errinfo->xlr_req)));
- }
- else if (errinfo->xlr_read == 0)
- {
- ereport(ERROR,
- (errcode(ERRCODE_DATA_CORRUPTED),
- errmsg("could not read from log segment %s, offset %u: read %d of %zu",
- fname, seg->ws_off, errinfo->xlr_read,
- (Size) errinfo->xlr_req)));
+ case WRE_OPER_SEEK:
+ errno = errinfo->xlr_errno;
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not seek in log segment %s to offset %u: %m",
+ fname, seg->ws_off)));
+ break;
+
+ case WRE_OPER_OPEN:
+ if (errinfo->xlr_read < 0)
+ {
+ errno = errinfo->xlr_errno;
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not read from log segment %s, offset %u, length %zu: %m",
+ fname, seg->ws_off, (Size) errinfo->xlr_req)));
+ }
+ else if (errinfo->xlr_read == 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("could not read from log segment %s, offset %u: read %d of %zu",
+ fname, seg->ws_off, errinfo->xlr_read,
+ (Size) errinfo->xlr_req)));
+ }
+ break;
}
}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 80ef5eb909..668537a6fb 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -248,8 +248,8 @@ static void LagTrackerWrite(XLogRecPtr lsn, TimestampTz local_flush_time);
static TimeOffset LagTrackerRead(int head, XLogRecPtr lsn, TimestampTz now);
static bool TransactionIdInRecentPast(TransactionId xid, uint32 epoch);
-static void WalSndSegmentOpen(XLogSegNo nextSegNo, WALSegmentContext *segcxt,
- TimeLineID *tli_p, int *file_p);
+static int WalSndSegmentOpen(XLogSegNo nextSegNo, WALSegmentContext *segcxt,
+ TimeLineID *tli_p);
/* Initialize walsender process before entering the main command loop */
@@ -789,16 +789,16 @@ logical_read_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, int req
count = flushptr - targetPagePtr; /* part of the page available */
/* now actually read the data, we know it's there */
- if (!XLogRead(cur_page,
- targetPagePtr,
- XLOG_BLCKSZ,
- sendSeg->ws_tli, /* Pass the current TLI because only
+ if (!WALRead(cur_page,
+ targetPagePtr,
+ XLOG_BLCKSZ,
+ sendSeg->ws_tli, /* Pass the current TLI because only
* WalSndSegmentOpen controls whether new
* TLI is needed. */
- sendSeg,
- sendCxt,
- WalSndSegmentOpen,
- &errinfo))
+ sendSeg,
+ sendCxt,
+ WalSndSegmentOpen,
+ &errinfo))
WALReadRaiseError(&errinfo);
/*
@@ -2376,11 +2376,12 @@ WalSndKill(int code, Datum arg)
/*
* Callback for XLogRead() to open the next segment.
*/
-void
+int
WalSndSegmentOpen(XLogSegNo nextSegNo, WALSegmentContext *segcxt,
- TimeLineID *tli_p, int *file_p)
+ TimeLineID *tli_p)
{
char path[MAXPGPATH];
+ int fd;
/*-------
* When reading from a historic timeline, and there is a timeline switch
@@ -2417,25 +2418,25 @@ WalSndSegmentOpen(XLogSegNo nextSegNo, WALSegmentContext *segcxt,
}
XLogFilePath(path, *tli_p, nextSegNo, segcxt->ws_segsize);
- *file_p = BasicOpenFile(path, O_RDONLY | PG_BINARY);
+ fd = BasicOpenFile(path, O_RDONLY | PG_BINARY);
+ if (fd >= 0)
+ return fd;
- if (*file_p < 0)
- {
- /*
- * If the file is not found, assume it's because the standby asked for
- * a too old WAL segment that has already been removed or recycled.
- */
- if (errno == ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("requested WAL segment %s has already been removed",
- XLogFileNameP(*tli_p, nextSegNo))));
- else
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not open file \"%s\": %m",
- path)));
- }
+ /*
+ * If the file is not found, assume it's because the standby asked for
+ * a too old WAL segment that has already been removed or recycled.
+ */
+ if (errno == ENOENT)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("requested WAL segment %s has already been removed",
+ XLogFileNameP(*tli_p, nextSegNo))));
+ else
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not open file \"%s\": %m",
+ path)));
+ return -1; /* keep compiler quiet */
}
/*
@@ -2674,16 +2675,16 @@ XLogSendPhysical(void)
enlargeStringInfo(&output_message, nbytes);
retry:
- if (!XLogRead(&output_message.data[output_message.len],
- startptr,
- nbytes,
- sendSeg->ws_tli, /* Pass the current TLI because only
+ if (!WALRead(&output_message.data[output_message.len],
+ startptr,
+ nbytes,
+ sendSeg->ws_tli, /* Pass the current TLI because only
* WalSndSegmentOpen controls whether new
* TLI is needed. */
- sendSeg,
- sendCxt,
- WalSndSegmentOpen,
- &errinfo))
+ sendSeg,
+ sendCxt,
+ WalSndSegmentOpen,
+ &errinfo))
WALReadRaiseError(&errinfo);
/* See logical_read_xlog_page(). */
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index f1908a8868..cb71d33f48 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -280,12 +280,13 @@ identify_target_directory(char *directory, char *fname)
return NULL; /* not reached */
}
-static void
+static int
WALDumpOpenSegment(XLogSegNo nextSegNo, WALSegmentContext *segcxt,
- TimeLineID *tli_p, int *file_p)
+ TimeLineID *tli_p)
{
TimeLineID tli = *tli_p;
char fname[MAXPGPATH];
+ int fd;
int tries;
XLogFileName(fname, tli, nextSegNo, segcxt->ws_segsize);
@@ -298,9 +299,9 @@ WALDumpOpenSegment(XLogSegNo nextSegNo, WALSegmentContext *segcxt,
*/
for (tries = 0; tries < 10; tries++)
{
- *file_p = open_file_in_directory(segcxt->ws_dir, fname);
- if (*file_p >= 0)
- break;
+ fd = open_file_in_directory(segcxt->ws_dir, fname);
+ if (fd >= 0)
+ return fd;
if (errno == ENOENT)
{
int save_errno = errno;
@@ -315,17 +316,16 @@ WALDumpOpenSegment(XLogSegNo nextSegNo, WALSegmentContext *segcxt,
break;
}
- if (*file_p < 0)
- fatal_error("could not find file \"%s\": %s",
- fname, strerror(errno));
+ fatal_error("could not find file \"%s\": %s", fname, strerror(errno));
+ return -1; /* keep compiler quiet */
}
/*
* XLogReader read_page callback
*/
static int
-XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
- XLogRecPtr targetPtr, char *readBuff)
+WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
+ XLogRecPtr targetPtr, char *readBuff)
{
XLogDumpPrivate *private = state->private_data;
int count = XLOG_BLCKSZ;
@@ -344,25 +344,31 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
}
- if (!XLogRead(readBuff, targetPagePtr, count, private->timeline,
- &state->seg, &state->segcxt, WALDumpOpenSegment, &errinfo))
+ if (!WALRead(readBuff, targetPagePtr, count, private->timeline,
+ &state->seg, &state->segcxt, WALDumpOpenSegment, &errinfo))
{
- WALOpenSegment *seg = errinfo.xlr_seg;
+ WALOpenSegment *seg = &errinfo.xlr_seg;
char fname[MAXPGPATH];
XLogFileName(fname, seg->ws_tli, seg->ws_segno,
state->segcxt.ws_segsize);
- if (errinfo.xlr_seek)
- fatal_error("could not seek in file %s to offset %u: %s",
- fname, seg->ws_off, strerror(errinfo.xlr_errno));
- else if (errinfo.xlr_errno != 0)
- fatal_error("could not read in file %s, offset %u, length %zu: %s",
- fname, seg->ws_off, (Size) errinfo.xlr_req,
- strerror(errinfo.xlr_errno));
- else
- fatal_error("could not read in file %s, offset %u: length: %zu",
- fname, seg->ws_off, (Size) errinfo.xlr_req);
+ switch (errinfo.xlr_oper)
+ {
+ case WRE_OPER_SEEK:
+ fatal_error("could not seek in file %s to offset %u: %s",
+ fname, seg->ws_off, strerror(errinfo.xlr_errno));
+ break;
+ case WRE_OPER_OPEN:
+ if (errinfo.xlr_errno != 0)
+ fatal_error("could not read in file %s, offset %u, length %zu: %s",
+ fname, seg->ws_off, (Size) errinfo.xlr_req,
+ strerror(errinfo.xlr_errno));
+ else
+ fatal_error("could not read in file %s, offset %u: length: %zu",
+ fname, seg->ws_off, (Size) errinfo.xlr_req);
+ break;
+ }
}
return count;
@@ -1026,7 +1032,7 @@ main(int argc, char **argv)
/* done with argument parsing, do the actual work */
/* we have everything we need, start reading */
- xlogreader_state = XLogReaderAllocate(WalSegSz, waldir, XLogDumpReadPage,
+ xlogreader_state = XLogReaderAllocate(WalSegSz, waldir, WALDumpReadPage,
&private);
if (!xlogreader_state)
fatal_error("out of memory");
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index 02d1514429..6b51538a62 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -217,9 +217,9 @@ extern XLogReaderState *XLogReaderAllocate(int wal_segment_size,
/* Free an XLogReader */
extern void XLogReaderFree(XLogReaderState *state);
-/* Initialize supporting structures */
/*
- * Callback to open the specified WAL segment for reading.
+ * Callback to open the specified WAL segment for reading. Returns a valid
+ * file descriptor when the file was opened successfully.
*
* "nextSegNo" is the number of the segment to be opened.
*
@@ -229,15 +229,13 @@ extern void XLogReaderFree(XLogReaderState *state);
* timeline in which the new segment should be found, but the callback can use
* it to return the TLI that it actually opened.
*
- * "file_p" points to an address the segment file descriptor should be stored
- * at.
- *
* BasicOpenFile() is the preferred way to open the segment file in backend
* code, whereas open(2) should be used in frontend.
*/
-typedef void (*WALSegmentOpen) (XLogSegNo nextSegNo, WALSegmentContext *segcxt,
- TimeLineID *tli_p, int *file_p);
+typedef int (*WALSegmentOpen) (XLogSegNo nextSegNo, WALSegmentContext *segcxt,
+ TimeLineID *tli_p);
+/* Initialize supporting structures */
extern void WALOpenSegmentInit(WALOpenSegment *seg, WALSegmentContext *segcxt,
int segsize, const char *waldir);
@@ -252,22 +250,29 @@ extern bool XLogReaderValidatePageHeader(XLogReaderState *state,
#ifdef FRONTEND
extern XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr);
#endif /* FRONTEND */
+
/*
- * Error information that both backend and frontend caller can process.
+ * Error information from WALRead that both backend and frontend caller can
+ * process.
*/
+typedef enum
+{
+ WRE_OPER_OPEN = (1 << 0),
+ WRE_OPER_SEEK = (1 << 1)
+} WALReadErrorOper;
typedef struct WALReadError
{
- bool xlr_seek; /* Error during lseek() ? */
+ WALReadErrorOper xlr_oper; /* operation that caused the error */
int xlr_errno; /* errno set by the last read() / lseek() */
int xlr_read; /* Bytes read by the last read(). */
int xlr_req; /* Bytes requested to be read. */
- WALOpenSegment *xlr_seg; /* Segment we tried to read from. */
+ WALOpenSegment xlr_seg; /* Segment we tried to read from. */
} WALReadError;
-extern bool XLogRead(char *buf, XLogRecPtr startptr, Size count,
- TimeLineID tli, WALOpenSegment *seg,
- WALSegmentContext *segcxt, WALSegmentOpen openSegment,
- WALReadError *errinfo);
+extern bool WALRead(char *buf, XLogRecPtr startptr, Size count,
+ TimeLineID tli, WALOpenSegment *seg,
+ WALSegmentContext *segcxt, WALSegmentOpen openSegment,
+ WALReadError *errinfo);
/* Functions for decoding an XLogRecord */
diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h
index 1ffc765c6a..3fe5b36748 100644
--- a/src/include/access/xlogutils.h
+++ b/src/include/access/xlogutils.h
@@ -55,4 +55,5 @@ extern void XLogReadDetermineTimeline(XLogReaderState *state,
XLogRecPtr wantPage, uint32 wantLength);
void WALReadRaiseError(WALReadError *errinfo);
+
#endif