Hi all,

I have been playing with the new APIs of xlogreader.h, and while
merging some of my stuff with 13, I found the handling around
->seg.ws_file overcomplicated and confusing as it is necessary for a
plugin to manipulate directly the fd of an opened segment in the WAL
segment open/close callbacks.

Wouldn't it be cleaner to limit the exposition of ->seg.ws_file to the
user if possible?  There are cases like a WAL sender where you cannot
do that, but something that came to my mind is to make
WALSegmentOpenCB return the fd of the opened segment, and pass down the
fd to close to WALSegmentCloseCB.  Then xlogreader.c is in charge of
resetting the field when a segment is closed.

Any thoughts?
--
Michael
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index c21b0ba972..fcf57b32eb 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -63,10 +63,10 @@ typedef int (*XLogPageReadCB) (XLogReaderState *xlogreader,
 							   int reqLen,
 							   XLogRecPtr targetRecPtr,
 							   char *readBuf);
-typedef void (*WALSegmentOpenCB) (XLogReaderState *xlogreader,
+typedef int (*WALSegmentOpenCB) (XLogReaderState *xlogreader,
 								  XLogSegNo nextSegNo,
 								  TimeLineID *tli_p);
-typedef void (*WALSegmentCloseCB) (XLogReaderState *xlogreader);
+typedef void (*WALSegmentCloseCB) (XLogReaderState *xlogreader, int fd);
 
 typedef struct XLogReaderRoutine
 {
@@ -93,10 +93,10 @@ typedef struct XLogReaderRoutine
 	XLogPageReadCB page_read;
 
 	/*
-	 * Callback to open the specified WAL segment for reading.  ->seg.ws_file
-	 * shall be set to the file descriptor of the opened segment.  In case of
-	 * failure, an error shall be raised by the callback and it shall not
-	 * return.
+	 * Callback to open the specified WAL segment for reading.  Needs to
+	 * return a file descriptor that will be saved as ->seg.ws_file,
+	 * indicating the opened WAL segment.  In case of failure, an error
+	 * shall be raised by the callback and it shall not return.
 	 *
 	 * "nextSegNo" is the number of the segment to be opened.
 	 *
@@ -107,8 +107,8 @@ typedef struct XLogReaderRoutine
 	WALSegmentOpenCB segment_open;
 
 	/*
-	 * WAL segment close callback.  ->seg.ws_file shall be set to a negative
-	 * number.
+	 * WAL segment close callback.  "fd" is the file descriptor of the
+	 * segment to close.
 	 */
 	WALSegmentCloseCB segment_close;
 } XLogReaderRoutine;
diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h
index e59b6cf3a9..c9cbdaffae 100644
--- a/src/include/access/xlogutils.h
+++ b/src/include/access/xlogutils.h
@@ -50,10 +50,10 @@ extern void FreeFakeRelcacheEntry(Relation fakerel);
 extern int	read_local_xlog_page(XLogReaderState *state,
 								 XLogRecPtr targetPagePtr, int reqLen,
 								 XLogRecPtr targetRecPtr, char *cur_page);
-extern void wal_segment_open(XLogReaderState *state,
+extern int	wal_segment_open(XLogReaderState *state,
 							 XLogSegNo nextSegNo,
 							 TimeLineID *tli_p);
-extern void wal_segment_close(XLogReaderState *state);
+extern void wal_segment_close(XLogReaderState *state, int fd);
 
 extern void XLogReadDetermineTimeline(XLogReaderState *state,
 									  XLogRecPtr wantPage, uint32 wantLength);
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 5995798b58..b026be4cbe 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -139,7 +139,10 @@ XLogReaderFree(XLogReaderState *state)
 	int			block_id;
 
 	if (state->seg.ws_file != -1)
-		state->routine.segment_close(state);
+	{
+		state->routine.segment_close(state, state->seg.ws_file);
+		state->seg.ws_file = -1;
+	}
 
 	for (block_id = 0; block_id <= XLR_MAX_BLOCK_ID; block_id++)
 	{
@@ -1089,10 +1092,13 @@ WALRead(XLogReaderState *state,
 			XLogSegNo	nextSegNo;
 
 			if (state->seg.ws_file >= 0)
-				state->routine.segment_close(state);
+			{
+				state->routine.segment_close(state, state->seg.ws_file);
+				state->seg.ws_file = -1;
+			}
 
 			XLByteToSeg(recptr, nextSegNo, state->segcxt.ws_segsize);
-			state->routine.segment_open(state, nextSegNo, &tli);
+			state->seg.ws_file = state->routine.segment_open(state, nextSegNo, &tli);
 
 			/* This shouldn't happen -- indicates a bug in segment_open */
 			Assert(state->seg.ws_file >= 0);
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 322b0e8ff5..6d3d8f6a53 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -784,17 +784,18 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa
 }
 
 /* XLogReaderRoutine->segment_open callback for local pg_wal files */
-void
+int
 wal_segment_open(XLogReaderState *state, XLogSegNo nextSegNo,
 				 TimeLineID *tli_p)
 {
 	TimeLineID	tli = *tli_p;
 	char		path[MAXPGPATH];
+	int			fd = -1;
 
 	XLogFilePath(path, tli, nextSegNo, state->segcxt.ws_segsize);
-	state->seg.ws_file = BasicOpenFile(path, O_RDONLY | PG_BINARY);
-	if (state->seg.ws_file >= 0)
-		return;
+	fd = BasicOpenFile(path, O_RDONLY | PG_BINARY);
+	if (fd >= 0)
+		return fd;
 
 	if (errno == ENOENT)
 		ereport(ERROR,
@@ -806,15 +807,16 @@ wal_segment_open(XLogReaderState *state, XLogSegNo nextSegNo,
 				(errcode_for_file_access(),
 				 errmsg("could not open file \"%s\": %m",
 						path)));
+
+	return -1;	/* keep compiler quiet */
 }
 
 /* stock XLogReaderRoutine->segment_close callback */
 void
-wal_segment_close(XLogReaderState *state)
+wal_segment_close(XLogReaderState *state, int fd)
 {
-	close(state->seg.ws_file);
+	close(fd);
 	/* need to check errno? */
-	state->seg.ws_file = -1;
 }
 
 /*
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 86847cbb54..c01eb2d2b6 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -254,7 +254,7 @@ 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(XLogReaderState *state, XLogSegNo nextSegNo,
+static int	WalSndSegmentOpen(XLogReaderState *state, XLogSegNo nextSegNo,
 							  TimeLineID *tli_p);
 static void UpdateSpillStats(LogicalDecodingContext *ctx);
 
@@ -316,7 +316,7 @@ WalSndErrorCleanup(void)
 	pgstat_report_wait_end();
 
 	if (xlogreader != NULL && xlogreader->seg.ws_file >= 0)
-		wal_segment_close(xlogreader);
+		wal_segment_close(xlogreader, xlogreader->seg.ws_file);
 
 	if (MyReplicationSlot != NULL)
 		ReplicationSlotRelease();
@@ -2456,11 +2456,12 @@ WalSndKill(int code, Datum arg)
 }
 
 /* XLogReaderRoutine->segment_open callback */
-static void
+static int
 WalSndSegmentOpen(XLogReaderState *state, XLogSegNo nextSegNo,
 				  TimeLineID *tli_p)
 {
 	char		path[MAXPGPATH];
+	int			fd = -1;
 
 	/*-------
 	 * When reading from a historic timeline, and there is a timeline switch
@@ -2497,9 +2498,9 @@ WalSndSegmentOpen(XLogReaderState *state, XLogSegNo nextSegNo,
 	}
 
 	XLogFilePath(path, *tli_p, nextSegNo, state->segcxt.ws_segsize);
-	state->seg.ws_file = BasicOpenFile(path, O_RDONLY | PG_BINARY);
-	if (state->seg.ws_file >= 0)
-		return;
+	fd = BasicOpenFile(path, O_RDONLY | PG_BINARY);
+	if (fd >= 0)
+		return fd;
 
 	/*
 	 * If the file is not found, assume it's because the standby asked for a
@@ -2522,6 +2523,8 @@ WalSndSegmentOpen(XLogReaderState *state, XLogSegNo nextSegNo,
 				(errcode_for_file_access(),
 				 errmsg("could not open file \"%s\": %m",
 						path)));
+
+	return -1;	/* keep compiler quiet */
 }
 
 /*
@@ -2686,7 +2689,7 @@ XLogSendPhysical(void)
 	{
 		/* close the current file. */
 		if (xlogreader->seg.ws_file >= 0)
-			wal_segment_close(xlogreader);
+			wal_segment_close(xlogreader, xlogreader->seg.ws_file);
 
 		/* Send CopyDone */
 		pq_putmessage_noblock('c', NULL, 0);
@@ -2791,7 +2794,7 @@ retry:
 
 		if (reload && xlogreader->seg.ws_file >= 0)
 		{
-			wal_segment_close(xlogreader);
+			wal_segment_close(xlogreader, xlogreader->seg.ws_file);
 
 			goto retry;
 		}
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index d1a0678935..6410a869f3 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -280,13 +280,14 @@ identify_target_directory(char *directory, char *fname)
 }
 
 /* pg_waldump's XLogReaderRoutine->segment_open callback */
-static void
+static int
 WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo,
 				   TimeLineID *tli_p)
 {
 	TimeLineID	tli = *tli_p;
 	char		fname[MAXPGPATH];
 	int			tries;
+	int			fd = -1;
 
 	XLogFileName(fname, tli, nextSegNo, state->segcxt.ws_segsize);
 
@@ -298,9 +299,9 @@ WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo,
 	 */
 	for (tries = 0; tries < 10; tries++)
 	{
-		state->seg.ws_file = open_file_in_directory(state->segcxt.ws_dir, fname);
-		if (state->seg.ws_file >= 0)
-			return;
+		fd = open_file_in_directory(state->segcxt.ws_dir, fname);
+		if (fd >= 0)
+			return fd;
 		if (errno == ENOENT)
 		{
 			int			save_errno = errno;
@@ -316,6 +317,7 @@ WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo,
 	}
 
 	fatal_error("could not find file \"%s\": %m", fname);
+	return -1;	/* keep compiler quiet */
 }
 
 /*
@@ -323,11 +325,10 @@ WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo,
  * wal_segment_close
  */
 static void
-WALDumpCloseSegment(XLogReaderState *state)
+WALDumpCloseSegment(XLogReaderState *state, int fd)
 {
-	close(state->seg.ws_file);
+	close(fd);
 	/* need to check errno? */
-	state->seg.ws_file = -1;
 }
 
 /* pg_waldump's XLogReaderRoutine->page_read callback */

Attachment: signature.asc
Description: PGP signature

Reply via email to