Re: Remove page-read callback from XLogReaderState.

2021-10-07 Thread Kyotaro Horiguchi
At Thu, 30 Sep 2021 09:40:06 +0900 (JST), Kyotaro Horiguchi 
 wrote in 
> At Mon, 27 Sep 2021 17:31:03 +1300, Thomas Munro  
> wrote in 
> > On Thu, Jul 15, 2021 at 4:48 PM Kyotaro Horiguchi
> >  wrote:
> > > Gah... Thank you for noticing me.  I thought that I have sent the
> > > rebased version. This is the rebased version on the current master.
> > 
> > Hi Kyotaro,
> > 
> > Did you see this?
> > 
> > https://www.postgresql.org/message-id/20210429022553.4h5qii5jb5eclu4i%40alap3.anarazel.de
> 
> Thank you for pinging me. I haven't noticed of that.
> I'll check on that line.

It looks like the XLogFindNextRecord was not finished. It should have
been turned into a state machine.

In this version (v18),

This contains only page-reader refactoring stuff.

- Rebased to the current master, including additional change for
  XLOG_OVERWRITE_CONTRECORD stuff. (This needed the new function
  XLogTerminateRead.)

- Finished XLogFindNextRecord including the fixup from Thomas' v17.

- Added a test for XLogFindNextRecord, on the behavior that
  page-skipping on seeking for the first record.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 2da06a9de78e4f2125bcc889d12e7e3ffdf1d4d4 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 30 Sep 2021 11:48:40 +0900
Subject: [PATCH v18 1/5] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Redesign the interface so that it asks the caller for more
data when required.  This model works better for proposed projects that
encryption, prefetching and other new features that would require
extending the callback interface for each case.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal(), then the remaining tasks of the
function are taken over by the new function XLogNeedData().

Author: Kyotaro HORIGUCHI 
Author: Heikki Linnakangas 
Reviewed-by: Antonin Houska 
Reviewed-by: Alvaro Herrera 
Reviewed-by: Takashi Menjo 
Reviewed-by: Thomas Munro 
Discussion: https://postgr.es/m/20190418.210257.43726183.horiguchi.kyotaro%40lab.ntt.co.jp
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 325 +++-
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  21 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  31 ++-
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 266 insertions(+), 159 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 26dcc00ac0..1557ceb8c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -918,7 +918,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4401,7 +4401,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -12300,7 +12299,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -12359,7 +12358,8 @@ retry:
 			readLen = 0;
 			readSource = XLOG_FROM_ANY;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -12469,7 +12469,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -12483,8 +12484,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 4b03577dcc..1d9976ecf4 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -39,8 +39,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			

Re: Remove page-read callback from XLogReaderState.

2021-09-29 Thread Kyotaro Horiguchi
At Mon, 27 Sep 2021 17:31:03 +1300, Thomas Munro  wrote 
in 
> On Thu, Jul 15, 2021 at 4:48 PM Kyotaro Horiguchi
>  wrote:
> > Gah... Thank you for noticing me.  I thought that I have sent the
> > rebased version. This is the rebased version on the current master.
> 
> Hi Kyotaro,
> 
> Did you see this?
> 
> https://www.postgresql.org/message-id/20210429022553.4h5qii5jb5eclu4i%40alap3.anarazel.de

Thank you for pinging me. I haven't noticed of that.
I'll check on that line.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2021-09-26 Thread Thomas Munro
On Thu, Jul 15, 2021 at 4:48 PM Kyotaro Horiguchi
 wrote:
> Gah... Thank you for noticing me.  I thought that I have sent the
> rebased version. This is the rebased version on the current master.

Hi Kyotaro,

Did you see this?

https://www.postgresql.org/message-id/20210429022553.4h5qii5jb5eclu4i%40alap3.anarazel.de




Re: Remove page-read callback from XLogReaderState.

2021-07-14 Thread Kyotaro Horiguchi
At Thu, 15 Jul 2021 00:39:52 +0500, Ibrar Ahmed  wrote 
in 
> On Wed, Jun 30, 2021 at 12:54 PM Kyotaro Horiguchi 
> wrote:
> > Maybe I will rebase it soon.
> >
> > Yes, rebase is required, therefore I am changing the status to "Waiting On
> Author"
> http://cfbot.cputube.org/patch_33_2113.log

Gah... Thank you for noticing me.  I thought that I have sent the
rebased version. This is the rebased version on the current master.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From cc36aefa3943e67d357be989044c951b5e6c0702 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Wed, 7 Jul 2021 13:10:34 +0900
Subject: [PATCH v21] Remove read_page callback from XLogReadRecord.

Previously, the XLogReader module would fetch new input data using a
callback function.  Redesign the interface so that it tells the caller
to insert more data with a return value instead.  This API suits later
patches for prefetching, encryption and probably other future features
that would otherwise require extending the callback interface for new
projects.

As incidental cleanup work, move global variables readOff, readLen and
readSegNo inside XlogReaderState.

Author: Kyotaro HORIGUCHI 
Author: Heikki Linnakangas  (earlier version)
Reviewed-by: Antonin Houska 
Reviewed-by: Alvaro Herrera 
Reviewed-by: Takashi Menjo 
Reviewed-by: Andres Freund 
Reviewed-by: Thomas Munro 
Discussion: https://postgr.es/m/20190418.210257.43726183.horiguchi.kyotaro%40lab.ntt.co.jp
---
 src/backend/access/transam/twophase.c |  14 +-
 src/backend/access/transam/xlog.c | 125 +--
 src/backend/access/transam/xlogreader.c   | 968 +++---
 src/backend/access/transam/xlogutils.c|  25 +-
 src/backend/replication/logical/logical.c |  26 +-
 .../replication/logical/logicalfuncs.c|  13 +-
 src/backend/replication/slotfuncs.c   |  18 +-
 src/backend/replication/walsender.c   |  42 +-
 src/bin/pg_rewind/parsexlog.c | 105 +-
 src/bin/pg_waldump/pg_waldump.c   | 141 +--
 src/include/access/xlogreader.h   | 157 +--
 src/include/access/xlogutils.h|   4 +-
 src/include/pg_config_manual.h|   2 +-
 src/include/replication/logical.h |  11 +-
 14 files changed, 955 insertions(+), 696 deletions(-)

diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6d3efb49a4..e0c1e8f334 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1330,11 +1330,8 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
 	char	   *errormsg;
 	TimeLineID	save_currtli = ThisTimeLineID;
 
-	xlogreader = XLogReaderAllocate(wal_segment_size, NULL,
-	XL_ROUTINE(.page_read = _local_xlog_page,
-			   .segment_open = _segment_open,
-			   .segment_close = _segment_close),
-	NULL);
+	xlogreader = XLogReaderAllocate(wal_segment_size, NULL, wal_segment_close);
+
 	if (!xlogreader)
 		ereport(ERROR,
 (errcode(ERRCODE_OUT_OF_MEMORY),
@@ -1342,7 +1339,12 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
  errdetail("Failed while allocating a WAL reading processor.")));
 
 	XLogBeginRead(xlogreader, lsn);
-	record = XLogReadRecord(xlogreader, );
+	while (XLogReadRecord(xlogreader, , ) ==
+		   XLREAD_NEED_DATA)
+	{
+		if (!read_local_xlog_page(xlogreader))
+			break;
+	}
 
 	/*
 	 * Restore immediately the timeline where it was previously, as
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c7c928f50b..f9aea2a689 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -819,17 +819,13 @@ static XLogSegNo openLogSegNo = 0;
 
 /*
  * These variables are used similarly to the ones above, but for reading
- * the XLOG.  readOff is the offset of the page just read, readLen
- * indicates how much of it has been read into readBuf, and readSource
+ * the XLOG.  readOff is the offset of the page just read, and readSource
  * indicates where we got the currently open file from.
  * Note: we could use Reserve/ReleaseExternalFD to track consumption of
  * this FD too; but it doesn't currently seem worthwhile, since the XLOG is
  * not read by general-purpose sessions.
  */
 static int	readFile = -1;
-static XLogSegNo readSegNo = 0;
-static uint32 readOff = 0;
-static uint32 readLen = 0;
 static XLogSource readSource = XLOG_FROM_ANY;
 
 /*
@@ -846,13 +842,6 @@ static XLogSource currentSource = XLOG_FROM_ANY;
 static bool lastSourceFailed = false;
 static bool pendingWalRcvRestart = false;
 
-typedef struct XLogPageReadPrivate
-{
-	int			emode;
-	bool		fetching_ckpt;	/* are we fetching a checkpoint record? */
-	bool		randAccess;
-} XLogPageReadPrivate;
-
 /*
  * These variables track when we last obtained some WAL data to process,
  * and where we got it from.  (XLogReceiptSource is initially the same as
@@ -927,10 +916,12 @@ static bool 

Re: Remove page-read callback from XLogReaderState.

2021-07-14 Thread Ibrar Ahmed
On Wed, Jun 30, 2021 at 12:54 PM Kyotaro Horiguchi 
wrote:

> At Fri, 09 Apr 2021 09:36:59 +0900 (JST), Kyotaro Horiguchi <
> horikyota@gmail.com> wrote in
> > I'm surprised to see this pushed this soon.  Thanks for pushing this!
>
> Then this has been reverted. I'm not sure how to check for the
> possible defect happens on that platform, but, anyways I reverted the
> CF item to "Needs Review" then moved to the next CF.
>
> Maybe I will rebase it soon.
>
> regards.
>
> --
> Kyotaro Horiguchi
> NTT Open Source Software Center
>
>
> Yes, rebase is required, therefore I am changing the status to "Waiting On
Author"
http://cfbot.cputube.org/patch_33_2113.log


-- 
Ibrar Ahmed


Re: Remove page-read callback from XLogReaderState.

2021-06-30 Thread Kyotaro Horiguchi
At Fri, 09 Apr 2021 09:36:59 +0900 (JST), Kyotaro Horiguchi 
 wrote in 
> I'm surprised to see this pushed this soon.  Thanks for pushing this!

Then this has been reverted. I'm not sure how to check for the
possible defect happens on that platform, but, anyways I reverted the
CF item to "Needs Review" then moved to the next CF.

Maybe I will rebase it soon.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2021-04-08 Thread Kyotaro Horiguchi
At Thu, 8 Apr 2021 23:51:34 +1200, Thomas Munro  wrote 
in 
> On Thu, Apr 8, 2021 at 9:46 PM Thomas Munro  wrote:
> > I squashed the patch set into one because half of them were fixups,
> > and the two main patches were really parts of the same change and
> > should go in together.
> >
> > I fixed a few compiler warnings (GCC 10.2 reported several
> > uninitialised variables, comparisons that are always true, etc) and
> > some comments.  You can see these in the fixup patch.
> 
> Pushed.  Luckily there are plenty more improvements possible for
> XLogReader/XLogDecoder in the next cycle.

I'm surprised to see this pushed this soon.  Thanks for pushing this!

And thanks for fixing the remaining mistakes including some stupid
ones..

At Thu, 8 Apr 2021 10:04:26 +1200, Thomas Munro  wrote 
in 
> There is a stray elog(HOGE) :-)

U!  This looks like getting slipped-in while investigating
another issue..  Thanks for preventing the repository from being
contaminated by such a thing..

At Thu, 8 Apr 2021 21:46:06 +1200, Thomas Munro  wrote 
in 
> I think maybe it it should really be XLogReaderSetInputData(state,
> tli, data, size) in a later release.  In the meantime, I changed it to
> XLogReaderSetInputData(state, size), hope that name make sense...

Sounds better. I didn't like that page-readers are allowed to touch
XLogReaderStats.seg directly. Anyway it would be a small change.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2021-04-08 Thread Thomas Munro
On Thu, Apr 8, 2021 at 9:46 PM Thomas Munro  wrote:
> I squashed the patch set into one because half of them were fixups,
> and the two main patches were really parts of the same change and
> should go in together.
>
> I fixed a few compiler warnings (GCC 10.2 reported several
> uninitialised variables, comparisons that are always true, etc) and
> some comments.  You can see these in the fixup patch.

Pushed.  Luckily there are plenty more improvements possible for
XLogReader/XLogDecoder in the next cycle.




Re: Remove page-read callback from XLogReaderState.

2021-04-08 Thread Thomas Munro
I squashed the patch set into one because half of them were fixups,
and the two main patches were really parts of the same change and
should go in together.

I fixed a few compiler warnings (GCC 10.2 reported several
uninitialised variables, comparisons that are always true, etc) and
some comments.  You can see these in the fixup patch.

+static inline void
+XLogReaderNotifySize(XLogReaderState *state, int32 len)

I think maybe it it should really be XLogReaderSetInputData(state,
tli, data, size) in a later release.  In the meantime, I changed it to
XLogReaderSetInputData(state, size), hope that name make sense...
From aa5ed37bef02bdbee2e11ad54f028e6bac54816a Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v20 1/5] Remove read_page callback from XLogReadRecord.

Previously, the XLogReader module would fetch new input data using a
callback function.  Redesign the interface so that it tells the caller
to insert more data with a return value instead.  This API suits later
patches for prefetching, encryption and probably other future features
that would otherwise require extending the callback interface for new
projects.

As incidental cleanup work, move global variables readOff, readLen and
readSegNo inside XlogReaderState.

Author: Kyotaro HORIGUCHI 
Author: Heikki Linnakangas  (earlier version)
Reviewed-by: Antonin Houska 
Reviewed-by: Alvaro Herrera 
Reviewed-by: Takashi Menjo 
Reviewed-by: Andres Freund 
Reviewed-by: Thomas Munro 
Discussion: https://postgr.es/m/20190418.210257.43726183.horiguchi.kyotaro%40lab.ntt.co.jp
---
 src/backend/access/transam/twophase.c |  14 +-
 src/backend/access/transam/xlog.c | 129 ++-
 src/backend/access/transam/xlogreader.c   | 932 +++---
 src/backend/access/transam/xlogutils.c|  25 +-
 src/backend/replication/logical/logical.c |  26 +-
 .../replication/logical/logicalfuncs.c|  13 +-
 src/backend/replication/slotfuncs.c   |  18 +-
 src/backend/replication/walsender.c   |  42 +-
 src/bin/pg_rewind/parsexlog.c | 107 +-
 src/bin/pg_waldump/pg_waldump.c   | 141 +--
 src/include/access/xlogreader.h   | 157 +--
 src/include/access/xlogutils.h|   4 +-
 src/include/pg_config_manual.h|   2 +-
 src/include/replication/logical.h |  11 +-
 14 files changed, 940 insertions(+), 681 deletions(-)

diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 89335b64a2..3137cb3ecc 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1330,11 +1330,8 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
 	char	   *errormsg;
 	TimeLineID	save_currtli = ThisTimeLineID;
 
-	xlogreader = XLogReaderAllocate(wal_segment_size, NULL,
-	XL_ROUTINE(.page_read = _local_xlog_page,
-			   .segment_open = _segment_open,
-			   .segment_close = _segment_close),
-	NULL);
+	xlogreader = XLogReaderAllocate(wal_segment_size, NULL, wal_segment_close);
+
 	if (!xlogreader)
 		ereport(ERROR,
 (errcode(ERRCODE_OUT_OF_MEMORY),
@@ -1342,7 +1339,12 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
  errdetail("Failed while allocating a WAL reading processor.")));
 
 	XLogBeginRead(xlogreader, lsn);
-	record = XLogReadRecord(xlogreader, );
+	while (XLogReadRecord(xlogreader, , ) ==
+		   XLREAD_NEED_DATA)
+	{
+		if (!read_local_xlog_page(xlogreader))
+			break;
+	}
 
 	/*
 	 * Restore immediately the timeline where it was previously, as
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c1d4415a43..d3d6fb4643 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -811,17 +811,13 @@ static XLogSegNo openLogSegNo = 0;
  * These variables are used similarly to the ones above, but for reading
  * the XLOG.  Note, however, that readOff generally represents the offset
  * of the page just read, not the seek position of the FD itself, which
- * will be just past that page. readLen indicates how much of the current
- * page has been read into readBuf, and readSource indicates where we got
- * the currently open file from.
+ * will be just past that page. readSource indicates where we got the
+ * currently open file from.
  * Note: we could use Reserve/ReleaseExternalFD to track consumption of
  * this FD too; but it doesn't currently seem worthwhile, since the XLOG is
  * not read by general-purpose sessions.
  */
 static int	readFile = -1;
-static XLogSegNo readSegNo = 0;
-static uint32 readOff = 0;
-static uint32 readLen = 0;
 static XLogSource readSource = XLOG_FROM_ANY;
 
 /*
@@ -838,13 +834,6 @@ static XLogSource currentSource = XLOG_FROM_ANY;
 static bool lastSourceFailed = false;
 static bool pendingWalRcvRestart = false;
 
-typedef struct XLogPageReadPrivate
-{
-	int			emode;
-	bool		fetching_ckpt;	

Re: Remove page-read callback from XLogReaderState.

2021-04-07 Thread Thomas Munro
On Wed, Apr 7, 2021 at 8:50 PM Kyotaro Horiguchi
 wrote:
> I haven't changed the name "XLog reader" to "XLog decoder". I'm doing
> that but it affects somewhat wide range of code.

Thanks for the new patch set!  Let's not worry about renaming it for now.

This fails in check-world as seen on cfbot; I am not 100% sure but
this change fixes it:

@@ -1231,7 +1231,7 @@ XLogFindNextRecord(XLogFindNextRecordState *state)
{
/* Rewind the reader to the beginning of the
last record. */
state->currRecPtr = state->reader_state->ReadRecPtr;
-   XLogBeginRead(state->reader_state, found);
+   XLogBeginRead(state->reader_state, state->currRecPtr);

The variable "found" seem to be useless.

I still see the 3 warnings mentioned earlier when compiling without
--enable-cassert.

There is a stray elog(HOGE) :-)




Re: Remove page-read callback from XLogReaderState.

2021-04-07 Thread Kyotaro Horiguchi
At Tue, 6 Apr 2021 16:09:55 -0700, Andres Freund  wrote in 
> Hi,
> 
> >  XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int 
> > reqLen,
> >  XLogRecPtr targetRecPtr, char *readBuf)
> >  {
> > @@ -12170,7 +12169,8 @@ retry:
> > readLen = 0;
> > readSource = XLOG_FROM_ANY;
> >  
> > -   return -1;
> > +   xlogreader->readLen = -1;
> > +   return false;
> > }
> > }
> 
> It seems a bit weird to assign to XlogReaderState->readLen inside the
> callbacks. I first thought it was just a transient state, but it's
> not. I think it'd be good to wrap the xlogreader->readLen assignment an
> an inline function. That we can add more asserts etc over time.

Sounds reasonable. The variable is split up into request/result
variables and setting the result variable is wrapped by a
function. (0005).

> > -/* pg_waldump's XLogReaderRoutine->page_read callback */
> > +/*
> > + * pg_waldump's WAL page rader, also used as page_read callback for
> > + * XLogFindNextRecord
> > + */
> >  static bool
> > -WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int 
> > reqLen,
> > -   XLogRecPtr targetPtr, char *readBuff)
> > +WALDumpReadPage(XLogReaderState *state, void *priv)
> >  {
> > -   XLogDumpPrivate *private = state->private_data;
> > +   XLogRecPtr  targetPagePtr = state->readPagePtr;
> > +   int reqLen= state->readLen;
> > +   char   *readBuff  = state->readBuf;
> > +   XLogDumpPrivate *private  = (XLogDumpPrivate *) priv;
> 
> It seems weird to pass a void *priv to a function that now doesn't at
> all need the type punning anymore.

Mmm. I omitted it since client code was somewhat out-of-scope.  In the
attached 0004 WALDumpReadPage() is no longer used as the callback of
XLogFindNextRecord.

On the way fixing them, I found that XLogReaderState.readPageTLI has
been moved to XLogReaderState.seg.ws_tli so I removed it from 0001.

I haven't changed the name "XLog reader" to "XLog decoder". I'm doing
that but it affects somewhat wide range of code.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From bda7ea561de0a8aec75eb50e8f07daaf96509583 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v19 1/5] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Redesign the interface so that it asks the caller for more
data when required.  This model works better for proposed projects that
encryption, prefetching and other new features that would require
extending the callback interface for each case.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal(), then the remaining tasks of the
function are taken over by the new function XLogNeedData().

Author: Kyotaro HORIGUCHI 
Author: Heikki Linnakangas 
Reviewed-by: Antonin Houska 
Reviewed-by: Alvaro Herrera 
Reviewed-by: Takashi Menjo 
Reviewed-by: Thomas Munro 
Discussion: https://postgr.es/m/20190418.210257.43726183.horiguchi.kyotaro%40lab.ntt.co.jp
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 325 +++-
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  21 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  32 ++-
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 267 insertions(+), 159 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c1d4415a43..8085ca1117 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -920,7 +920,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4375,7 +4375,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -12107,7 +12106,7 @@ CancelBackup(void)
  * XLogPageRead() to try 

Re: Remove page-read callback from XLogReaderState.

2021-04-06 Thread Alvaro Herrera
On 2021-Apr-07, Thomas Munro wrote:

> On Wed, Apr 7, 2021 at 11:18 AM Alvaro Herrera  
> wrote:
> > BTRW it's funny that after these patches, "xlogreader" no longer reads
> > anything.  It's more an "xlog interpreter" -- the piece of code that
> > splits individual WAL records from a stream of WAL bytes that's caller's
> > responsibility to obtain somehow.  But (and, again, I haven't read this
> > patch recently) it still offers pieces that support a reader, in
> > addition to its main interface as the interpreter.  Maybe it's not a
> > totally stupid idea to split it in even more different files.
> 
> Yeah, I like "decoder", and it's already called that in some places...

Yeah, that works ...

-- 
Álvaro Herrera39°49'30"S 73°17'W
"Los trabajadores menos efectivos son sistematicamente llevados al lugar
donde pueden hacer el menor daño posible: gerencia."  (El principio Dilbert)




Re: Remove page-read callback from XLogReaderState.

2021-04-06 Thread Thomas Munro
On Wed, Apr 7, 2021 at 11:18 AM Alvaro Herrera  wrote:
> BTRW it's funny that after these patches, "xlogreader" no longer reads
> anything.  It's more an "xlog interpreter" -- the piece of code that
> splits individual WAL records from a stream of WAL bytes that's caller's
> responsibility to obtain somehow.  But (and, again, I haven't read this
> patch recently) it still offers pieces that support a reader, in
> addition to its main interface as the interpreter.  Maybe it's not a
> totally stupid idea to split it in even more different files.

Yeah, I like "decoder", and it's already called that in some places...




Re: Remove page-read callback from XLogReaderState.

2021-04-06 Thread Alvaro Herrera
On 2021-Apr-07, Thomas Munro wrote:

> I wonder if it would be better to have the client code access these
> values through functions (even if they just access the variables in a
> static inline function), to create a bit more separation?  Something
> like XLogReaderGetWanted(_lsn, _wanted), and then
> XLogReaderSetAvailable(state, 42)?  Just an idea.

I think more opacity is good in this area, generally speaking.  There
are way too many globals, and they interact in nontrivial ways across
the codebase.  Just look at the ThisTimeLineID recent disaster.  I
don't have this patch sufficiently paged-in to say that bytes_wanted/
bytes_available is precisely the thing we need, but if it makes for a
cleaner interface, I'm for it.  This module keeps some state inside
itself, and others part of the state is in its users; that's not good,
and any cleanup on that is welcome.

BTRW it's funny that after these patches, "xlogreader" no longer reads
anything.  It's more an "xlog interpreter" -- the piece of code that
splits individual WAL records from a stream of WAL bytes that's caller's
responsibility to obtain somehow.  But (and, again, I haven't read this
patch recently) it still offers pieces that support a reader, in
addition to its main interface as the interpreter.  Maybe it's not a
totally stupid idea to split it in even more different files.

-- 
Álvaro Herrera39°49'30"S 73°17'W




Re: Remove page-read callback from XLogReaderState.

2021-04-06 Thread Andres Freund
Hi,

On 2021-04-07 05:09:53 +1200, Thomas Munro wrote:
> From 560cdfa444a3b05a0e6b8054f3cfeadf56e059fc Mon Sep 17 00:00:00 2001
> From: Kyotaro Horiguchi 
> Date: Thu, 5 Sep 2019 20:21:55 +0900
> Subject: [PATCH v18 1/3] Move callback-call from ReadPageInternal to
>  XLogReadRecord.
> 
> The current WAL record reader reads page data using a call back
> function.  Redesign the interface so that it asks the caller for more
> data when required.  This model works better for proposed projects that
> encryption, prefetching and other new features that would require
> extending the callback interface for each case.
> 
> As the first step of that change, this patch moves the page reader
> function out of ReadPageInternal(), then the remaining tasks of the
> function are taken over by the new function XLogNeedData().

> -static int
> +static bool
>  XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int 
> reqLen,
>XLogRecPtr targetRecPtr, char *readBuf)
>  {
> @@ -12170,7 +12169,8 @@ retry:
>   readLen = 0;
>   readSource = XLOG_FROM_ANY;
>  
> - return -1;
> + xlogreader->readLen = -1;
> + return false;
>   }
>   }

It seems a bit weird to assign to XlogReaderState->readLen inside the
callbacks. I first thought it was just a transient state, but it's
not. I think it'd be good to wrap the xlogreader->readLen assignment an
an inline function. That we can add more asserts etc over time.



> -/* pg_waldump's XLogReaderRoutine->page_read callback */
> +/*
> + * pg_waldump's WAL page rader, also used as page_read callback for
> + * XLogFindNextRecord
> + */
>  static bool
> -WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
> - XLogRecPtr targetPtr, char *readBuff)
> +WALDumpReadPage(XLogReaderState *state, void *priv)
>  {
> - XLogDumpPrivate *private = state->private_data;
> + XLogRecPtr  targetPagePtr = state->readPagePtr;
> + int reqLen= state->readLen;
> + char   *readBuff  = state->readBuf;
> + XLogDumpPrivate *private  = (XLogDumpPrivate *) priv;

It seems weird to pass a void *priv to a function that now doesn't at
all need the type punning anymore.

Greetings,

Andres Freund




Re: Remove page-read callback from XLogReaderState.

2021-04-06 Thread Thomas Munro
On Wed, Apr 7, 2021 at 5:09 AM Thomas Munro  wrote:
> 0001 + 0002 get rid of the callback interface and replace it with a
> state machine, making it the client's problem to supply data when it
> returns XLREAD_NEED_DATA.  I found this interface nicer to work with,
> for my WAL decoding buffer patch (CF 2410), and I understand that the
> encryption patch set can also benefit from it.  Certainly when I
> rebased my project on this patch set, I prefered the result.

+state->readLen = pageHeaderSize;

This variable is used for the XLogPageReader to say how much data it
wants, but also for the caller to indicate how much data is loaded.
Wouldn't it be better to split this into two variables: bytesWanted
and bytesAvailable?  (I admit that I spent a whole afternoon debugging
after confusing myself about that, when rebasing my WAL readahead
patch recently).

I wonder if it would be better to have the client code access these
values through functions (even if they just access the variables in a
static inline function), to create a bit more separation?  Something
like XLogReaderGetWanted(_lsn, _wanted), and then
XLogReaderSetAvailable(state, 42)?  Just an idea.




Re: Remove page-read callback from XLogReaderState.

2021-04-06 Thread Thomas Munro
On Wed, Mar 31, 2021 at 7:17 PM Kyotaro Horiguchi
 wrote:
> At Wed, 31 Mar 2021 10:00:02 +1300, Thomas Munro  
> wrote in
> > On Thu, Mar 4, 2021 at 3:29 PM Kyotaro Horiguchi
> >  wrote:
> > > A recent commot about LSN_FORMAT_ARGS conflicted this.
> > > Just rebased.
> >
> > FYI I've been looking at this, and I think it's a very nice
> > improvement.  I'll post some review comments and a rebase shortly.
>
> Thanks for looking at this!

I rebased and pgindent-ed the first three patches and did some
testing.  I think it looks pretty good, though I still need to check
the code coverage when running the recovery tests.  There are three
compiler warnings from GCC when not using --enable-cassert, including
uninitialized variables: pageHeader and targetPagePtr.  It looks like
they could be silenced as follows, or maybe you see a better way?

-   XLogPageHeader pageHeader;
+   XLogPageHeader pageHeader = NULL;
uint32  pageHeaderSize;
-   XLogRecPtr  targetPagePtr;
+   XLogRecPtr  targetPagePtr =
InvalidXLogRecPtr;

To summarise the patches:

0001 + 0002 get rid of the callback interface and replace it with a
state machine, making it the client's problem to supply data when it
returns XLREAD_NEED_DATA.  I found this interface nicer to work with,
for my WAL decoding buffer patch (CF 2410), and I understand that the
encryption patch set can also benefit from it.  Certainly when I
rebased my project on this patch set, I prefered the result.

0003 is nice global variable cleanup.

I haven't looked at 0004.
From 560cdfa444a3b05a0e6b8054f3cfeadf56e059fc Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v18 1/3] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Redesign the interface so that it asks the caller for more
data when required.  This model works better for proposed projects that
encryption, prefetching and other new features that would require
extending the callback interface for each case.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal(), then the remaining tasks of the
function are taken over by the new function XLogNeedData().

Author: Kyotaro HORIGUCHI 
Author: Heikki Linnakangas 
Reviewed-by: Antonin Houska 
Reviewed-by: Alvaro Herrera 
Reviewed-by: Takashi Menjo 
Reviewed-by: Thomas Munro 
Discussion: https://postgr.es/m/20190418.210257.43726183.horiguchi.kyotaro%40lab.ntt.co.jp
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 277 ++--
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  21 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  33 +--
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 224 insertions(+), 155 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 6f8810e149..449e17d2fa 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -920,7 +920,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4375,7 +4375,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -12111,7 +12110,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -12170,7 +12169,8 @@ retry:
 			readLen = 0;
 			readSource = XLOG_FROM_ANY;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -12265,7 +12265,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;

Re: Remove page-read callback from XLogReaderState.

2021-03-31 Thread Kyotaro Horiguchi
At Wed, 31 Mar 2021 10:00:02 +1300, Thomas Munro  wrote 
in 
> On Thu, Mar 4, 2021 at 3:29 PM Kyotaro Horiguchi
>  wrote:
> > A recent commot about LSN_FORMAT_ARGS conflicted this.
> > Just rebased.
> 
> FYI I've been looking at this, and I think it's a very nice
> improvement.  I'll post some review comments and a rebase shortly.

Thanks for looking at this!

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2021-03-30 Thread Thomas Munro
On Thu, Mar 4, 2021 at 3:29 PM Kyotaro Horiguchi
 wrote:
> A recent commot about LSN_FORMAT_ARGS conflicted this.
> Just rebased.

FYI I've been looking at this, and I think it's a very nice
improvement.  I'll post some review comments and a rebase shortly.




Re: Remove page-read callback from XLogReaderState.

2021-03-03 Thread Kyotaro Horiguchi
A recent commot about LSN_FORMAT_ARGS conflicted this.
Just rebased.

regards
-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From b23cb65696a42e32b657f12bcf2355acd3100084 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v17 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 281 ++--
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  21 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  25 ++-
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 222 insertions(+), 153 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 377afb8732..606328a65a 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -917,7 +917,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4350,7 +4350,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -11987,7 +11986,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -12046,7 +12045,8 @@ retry:
 			readLen = 0;
 			readSource = XLOG_FROM_ANY;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -12141,7 +12141,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -12155,8 +12156,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 42738eb940..7d04995b7b 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -36,8 +36,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
 static void XLogReaderInvalReadState(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
@@ -276,7 +276,6 @@ XLogReadRecord(XLogReaderState *state, char **errormsg)
 	uint32		targetRecOff;
 	uint32		pageHeaderSize;
 	bool		gotheader;
-	int			readOff;
 
 	/*
 	 * randAccess indicates whether to verify the previous-record pointer of
@@ -326,14 +325,20 @@ XLogReadRecord(XLogReaderState *state, 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,
-	

Re: Remove page-read callback from XLogReaderState.

2020-09-08 Thread Kyotaro Horiguchi
Thank you for the comment and sorry for late reply.

At Fri, 17 Jul 2020 14:14:44 +0900, Takashi Menjo  
wrote in 
> Hi,
> 
> I applied your v15 patchset to master
> ed2c7f65bd9f15f8f7cd21ad61602f983b1e72e9.  Here are three feedback points
> for you:
> 
> = 1. Build error when WAL_DEBUG is defined manually =
..
> Expected: PostgreSQL is successfully made.
> Actual: I got the following make error:
...
> 1219 |debug_reader = XLogReaderAllocate(wal_segment_size, NULL NULL);

Ah, I completely forgot about WAL_DEBUG paths. Fixed.

> = 2. readBuf allocation in XLogReaderAllocate =
> AFAIU, not XLogReaderAllocate() itself but its caller is now responsible
> for allocating XLogReaderState->readBuf.  However, the following code still
> remains in src/backend/access/transam/xlogreader.c:
> 
> 
>  74 XLogReaderState *
>  75 XLogReaderAllocate(int wal_segment_size, const char *waldir,
>  76WALSegmentCleanupCB cleanup_cb)
>  77 {
>   :
>  98 state->readBuf = (char *) palloc_extended(XLOG_BLCKSZ,
>  99   MCXT_ALLOC_NO_OOM);
> 
> 
> Is this okay?

Oops! That's silly. However, I put a rethink on this.  The reason of
the moving of responsibility comes from the fact that the actual
subject that fills-in the buffer is the callers of xlogreader, who
knows its size.  In that light it's quite strange that xlogreader
works based on the fixed size of XLOG_BLCKSZ. I don't think it is
useful just now, but I changed 0004 so that XLOG_BLCKSZ is eliminated
from xlogreader.c. Buffer allocation is restored to
XLogReaderAllocate.

(But, I'm not sure it's worth doing..)

> = 3. XLOG_FROM_ANY assigned to global readSource =
> Regarding the following chunk in 0003:
...
> -static XLogSource readSource = XLOG_FROM_ANY;
> +static XLogSource readSource = 0;  /* XLOG_FROM_* code */
> 
> I think it is better to keep the line "static XLogSource readSource =
> XLOG_FROM_ANY;".  XLOG_FROM_ANY is already defined as 0 in
> src/backend/access/transam/xlog.c.

That seems to be a mistake while past rebasding. XLOG_FROM_ANY is the
right thing to use here.

The attached is the rebased, and fixed version.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 84a2f6b1abe2e34b4cdfcb7da7380a2d6161b292 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v16 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 281 ++--
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  21 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  25 ++-
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 222 insertions(+), 153 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 09c01ed4ae..a91e86b290 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -909,7 +909,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4329,7 +4329,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -11866,7 

Re: Remove page-read callback from XLogReaderState.

2020-09-07 Thread Kyotaro Horiguchi
At Tue, 08 Sep 2020 11:56:29 +0900 (JST), Kyotaro Horiguchi 
 wrote in 
> Thank you for the comment, Menjo-san, and noticing me of that, Michael.

I found why the message I was writing was gone from the draft folder..

Sorry for the garbage.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2020-09-07 Thread Kyotaro Horiguchi
Thank you for the comment, Menjo-san, and noticing me of that, Michael.

Sorry for late reply.

At Fri, 17 Jul 2020 14:14:44 +0900, Takashi Menjo  
wrote in 
> Hi,
> 
> I applied your v15 patchset to master
> ed2c7f65bd9f15f8f7cd21ad61602f983b1e72e9.  Here are three feedback points
> for you:
> 
> 
> = 1. Build error when WAL_DEBUG is defined manually =
> How to reproduce:
> 
>  $ sed -i -E -e 's|^/\* #define WAL_DEBUG \*/$|#define WAL_DEBUG|'
> src/include/pg_config_manual.h
>  $ ./configure && make
> 
> Expected: PostgreSQL is successfully made.
> Actual: I got the following make error:
> 
> 
> gcc -Wall -Wmissing-prototypes -Wpointer-arith
> -Wdeclaration-after-statement -Werror=vla -Wendif-labels
> -Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type
> -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard
> -Wno-format-truncation -Wno-stringop-truncation -O2
> -I../../../../src/include  -D_GNU_SOURCE   -c -o xlog.o xlog.c
> In file included from /usr/include/x86_64-linux-gnu/bits/types/stack_t.h:23,
>  from /usr/include/signal.h:303,
>  from ../../../../src/include/storage/sinval.h:17,
>  from ../../../../src/include/access/xact.h:22,
>  from ../../../../src/include/access/twophase.h:17,
>  from xlog.c:33:
> xlog.c: In function ‘XLogInsertRecord’:
> xlog.c:1219:56: error: called object is not a function or function pointer
>  1219 |debug_reader = XLogReaderAllocate(wal_segment_size, NULL NULL);
>   |^~~~
> xlog.c:1219:19: error: too few arguments to function ‘XLogReaderAllocate’
>  1219 |debug_reader = XLogReaderAllocate(wal_segment_size, NULL NULL);
>   |   ^~
> In file included from ../../../../src/include/access/clog.h:14,
>  from xlog.c:25:
> ../../../../src/include/access/xlogreader.h:243:25: note: declared here
>   243 | extern XLogReaderState *XLogReaderAllocate(int wal_segment_size,
>   | ^~
> make[4]: *** [: xlog.o] Error 1
> 
> 
> The following chunk in 0002 seems to be the cause of the error.  There is
> no comma between two NULLs.
> 
> 
> diff --git a/src/backend/access/transam/xlog.c
> b/src/backend/access/transam/xlog.c
> index e570e56a24..f9b0108602 100644
> --- a/src/backend/access/transam/xlog.c
> +++ b/src/backend/access/transam/xlog.c
> (..snipped..)
> @@ -1225,8 +1218,7 @@ XLogInsertRecord(XLogRecData *rdata,
> appendBinaryStringInfo(, rdata->data, rdata->len);
> 
> if (!debug_reader)
> -   debug_reader = XLogReaderAllocate(wal_segment_size, NULL,
> - XL_ROUTINE(), NULL);
> +   debug_reader = XLogReaderAllocate(wal_segment_size, NULL NULL);
> 
> if (!debug_reader)
> {
> 
> 
> 
> = 2. readBuf allocation in XLogReaderAllocate =
> AFAIU, not XLogReaderAllocate() itself but its caller is now responsible
> for allocating XLogReaderState->readBuf.  However, the following code still
> remains in src/backend/access/transam/xlogreader.c:
> 
> 
>  74 XLogReaderState *
>  75 XLogReaderAllocate(int wal_segment_size, const char *waldir,
>  76WALSegmentCleanupCB cleanup_cb)
>  77 {
>   :
>  98 state->readBuf = (char *) palloc_extended(XLOG_BLCKSZ,
>  99   MCXT_ALLOC_NO_OOM);
> 
> 
> Is this okay?
> 
> 
> = 3. XLOG_FROM_ANY assigned to global readSource =
> Regarding the following chunk in 0003:
> 
> 
> diff --git a/src/backend/access/transam/xlog.c
> b/src/backend/access/transam/xlog.c
> index 6b42d9015f..bcb4ef270f 100644
> --- a/src/backend/access/transam/xlog.c
> +++ b/src/backend/access/transam/xlog.c
> @@ -804,18 +804,14 @@ static XLogSegNo openLogSegNo = 0;
>   * These variables are used similarly to the ones above, but for reading
>   * the XLOG.  Note, however, that readOff generally represents the offset
>   * of the page just read, not the seek position of the FD itself, which
> - * will be just past that page. readLen indicates how much of the current
> - * page has been read into readBuf, and readSource indicates where we got
> - * the currently open file from.
> + * will be just past that page. readSource indicates where we got the
> + * currently open file from.
>   * Note: we could use Reserve/ReleaseExternalFD to track consumption of
>   * this FD too; but it doesn't currently seem worthwhile, since the XLOG is
>   * not read by general-purpose sessions.
>   */
>  static int readFile = -1;
> -static XLogSegNo readSegNo = 0;
> -static uint32 readOff = 0;
> -static uint32 readLen = 0;
> -static XLogSource readSource = XLOG_FROM_ANY;
> +static XLogSource readSource = 0;  /* XLOG_FROM_* code */
> 
>  /*
>   * Keeps track of which source we're 

Re: Remove page-read callback from XLogReaderState.

2020-09-06 Thread Michael Paquier
On Fri, Jul 17, 2020 at 02:14:44PM +0900, Takashi Menjo wrote:
> I applied your v15 patchset to master
> ed2c7f65bd9f15f8f7cd21ad61602f983b1e72e9.  Here are three feedback points
> for you:

And the CF bot complains as well here.  Horiguchi-san, this patch is
waiting on author for a couple of weeks now.  Could you rebase the
patch and comment on the points raised upthread?
--
Michael


signature.asc
Description: PGP signature


Re: Remove page-read callback from XLogReaderState.

2020-07-16 Thread Takashi Menjo
Hi,

I applied your v15 patchset to master
ed2c7f65bd9f15f8f7cd21ad61602f983b1e72e9.  Here are three feedback points
for you:


= 1. Build error when WAL_DEBUG is defined manually =
How to reproduce:

 $ sed -i -E -e 's|^/\* #define WAL_DEBUG \*/$|#define WAL_DEBUG|'
src/include/pg_config_manual.h
 $ ./configure && make

Expected: PostgreSQL is successfully made.
Actual: I got the following make error:


gcc -Wall -Wmissing-prototypes -Wpointer-arith
-Wdeclaration-after-statement -Werror=vla -Wendif-labels
-Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type
-Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard
-Wno-format-truncation -Wno-stringop-truncation -O2
-I../../../../src/include  -D_GNU_SOURCE   -c -o xlog.o xlog.c
In file included from /usr/include/x86_64-linux-gnu/bits/types/stack_t.h:23,
 from /usr/include/signal.h:303,
 from ../../../../src/include/storage/sinval.h:17,
 from ../../../../src/include/access/xact.h:22,
 from ../../../../src/include/access/twophase.h:17,
 from xlog.c:33:
xlog.c: In function ‘XLogInsertRecord’:
xlog.c:1219:56: error: called object is not a function or function pointer
 1219 |debug_reader = XLogReaderAllocate(wal_segment_size, NULL NULL);
  |^~~~
xlog.c:1219:19: error: too few arguments to function ‘XLogReaderAllocate’
 1219 |debug_reader = XLogReaderAllocate(wal_segment_size, NULL NULL);
  |   ^~
In file included from ../../../../src/include/access/clog.h:14,
 from xlog.c:25:
../../../../src/include/access/xlogreader.h:243:25: note: declared here
  243 | extern XLogReaderState *XLogReaderAllocate(int wal_segment_size,
  | ^~
make[4]: *** [: xlog.o] Error 1


The following chunk in 0002 seems to be the cause of the error.  There is
no comma between two NULLs.


diff --git a/src/backend/access/transam/xlog.c
b/src/backend/access/transam/xlog.c
index e570e56a24..f9b0108602 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
(..snipped..)
@@ -1225,8 +1218,7 @@ XLogInsertRecord(XLogRecData *rdata,
appendBinaryStringInfo(, rdata->data, rdata->len);

if (!debug_reader)
-   debug_reader = XLogReaderAllocate(wal_segment_size, NULL,
- XL_ROUTINE(), NULL);
+   debug_reader = XLogReaderAllocate(wal_segment_size, NULL NULL);

if (!debug_reader)
{



= 2. readBuf allocation in XLogReaderAllocate =
AFAIU, not XLogReaderAllocate() itself but its caller is now responsible
for allocating XLogReaderState->readBuf.  However, the following code still
remains in src/backend/access/transam/xlogreader.c:


 74 XLogReaderState *
 75 XLogReaderAllocate(int wal_segment_size, const char *waldir,
 76WALSegmentCleanupCB cleanup_cb)
 77 {
  :
 98 state->readBuf = (char *) palloc_extended(XLOG_BLCKSZ,
 99   MCXT_ALLOC_NO_OOM);


Is this okay?


= 3. XLOG_FROM_ANY assigned to global readSource =
Regarding the following chunk in 0003:


diff --git a/src/backend/access/transam/xlog.c
b/src/backend/access/transam/xlog.c
index 6b42d9015f..bcb4ef270f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -804,18 +804,14 @@ static XLogSegNo openLogSegNo = 0;
  * These variables are used similarly to the ones above, but for reading
  * the XLOG.  Note, however, that readOff generally represents the offset
  * of the page just read, not the seek position of the FD itself, which
- * will be just past that page. readLen indicates how much of the current
- * page has been read into readBuf, and readSource indicates where we got
- * the currently open file from.
+ * will be just past that page. readSource indicates where we got the
+ * currently open file from.
  * Note: we could use Reserve/ReleaseExternalFD to track consumption of
  * this FD too; but it doesn't currently seem worthwhile, since the XLOG is
  * not read by general-purpose sessions.
  */
 static int readFile = -1;
-static XLogSegNo readSegNo = 0;
-static uint32 readOff = 0;
-static uint32 readLen = 0;
-static XLogSource readSource = XLOG_FROM_ANY;
+static XLogSource readSource = 0;  /* XLOG_FROM_* code */

 /*
  * Keeps track of which source we're currently reading from. This is


I think it is better to keep the line "static XLogSource readSource =
XLOG_FROM_ANY;".  XLOG_FROM_ANY is already defined as 0 in
src/backend/access/transam/xlog.c.


Regards,
Takashi



2020年7月2日(木) 13:53 Kyotaro Horiguchi :

> cfbot is complaining as this is no longer applicable. Rebased.
>
> In v14, some reference to XLogReaderState parameter to 

Re: Remove page-read callback from XLogReaderState.

2020-07-01 Thread Kyotaro Horiguchi
cfbot is complaining as this is no longer applicable. Rebased.

In v14, some reference to XLogReaderState parameter to read_pages
functions are accidentally replaced by the reference to the global
variable xlogreader. Fixed it, too.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From a4584ab5deddd49325c2f8e3fd78de406c95ce89 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v15 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 281 ++--
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  21 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  25 ++-
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 222 insertions(+), 153 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index fd93bcfaeb..e570e56a24 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -912,7 +912,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4332,7 +4332,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -11860,7 +11859,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11919,7 +11918,8 @@ retry:
 			readLen = 0;
 			readSource = XLOG_FROM_ANY;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -12014,7 +12014,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -12028,8 +12029,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index cb76be4f46..3d599325ee 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -36,8 +36,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
 static void XLogReaderInvalReadState(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
@@ -276,7 +276,6 @@ XLogReadRecord(XLogReaderState *state, char **errormsg)
 	uint32		targetRecOff;
 	uint32		pageHeaderSize;
 	bool		gotheader;
-	int			readOff;
 
 	/*
 	 * randAccess indicates whether to verify the previous-record pointer of
@@ -326,14 +325,20 @@ XLogReadRecord(XLogReaderState *state, char 

Re: Remove page-read callback from XLogReaderState.

2020-05-26 Thread Kyotaro Horiguchi
Thank you for the comment.

At Tue, 26 May 2020 20:17:47 +0800, Craig Ringer  wrote 
in 
> On Tue, 26 May 2020, 15:40 Kyotaro Horiguchi, 
> wrote:
> 
> >
> > This patch removes all the three callbacks (open/close/page_read) in
> > XL_ROUTINE from XLogReaderState.  It only has "cleanup" callback
> > instead.
> >
> 
> I actually have a use in mind for these callbacks - to support reading WAL
> for logical decoding from a restore_command like tool. So we can archive
> wal when it's no longer required for recovery and reduce the risk of
> filling pg_wal if a standby lags.
> 
> I don't object to your cleanup at all. I'd like it to  be properly
> pluggable, whereas right now it has hard coded callbacks that differ for
> little reason.
>
> Just noting that the idea of a callback here isn't a bad thing.

I agree that plugin is generally not bad as far as it were standalone,
that is, as far as it is not tightly cooperative with the opposite
side of the caller of it.  However, actually it seems to me that the
xlogreader plugins are too-deeply coupled with the callers of
xlogreader in many aspects involving error-handling and
retry-mechanism.

As Alvaro mentioned we may have page-decrypt callback shortly as
another callback of xlogreader.  Xlogreader could be more messy by
introducing such plugins, that actually have no business with
xlogreader at all.

Evidently xlogreader can be a bottom-end module (that is, a module
that doesn't depend on another module). It is I think a good thing to
isolate xlogreader from the changes of its callers and correlated
plugins.

A major problem of this patch is that the state machine used there
might be another mess here, though.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2020-05-26 Thread Craig Ringer
On Tue, 26 May 2020, 15:40 Kyotaro Horiguchi, 
wrote:

>
> This patch removes all the three callbacks (open/close/page_read) in
> XL_ROUTINE from XLogReaderState.  It only has "cleanup" callback
> instead.
>

I actually have a use in mind for these callbacks - to support reading WAL
for logical decoding from a restore_command like tool. So we can archive
wal when it's no longer required for recovery and reduce the risk of
filling pg_wal if a standby lags.

I don't object to your cleanup at all. I'd like it to  be properly
pluggable, whereas right now it has hard coded callbacks that differ for
little reason.

Just noting that the idea of a callback here isn't a bad thing.

>


Re: Remove page-read callback from XLogReaderState.

2020-05-26 Thread Kyotaro Horiguchi
At Wed, 22 Apr 2020 10:12:46 +0900 (JST), Kyotaro Horiguchi 
 wrote in 
> cd12323440 conflicts with this. Rebased.

b060dbe000 is conflicting.  I gave up isolating XLogOpenSegment from
xlogreader.c, since the two are tightly coupled than I thought.

This patch removes all the three callbacks (open/close/page_read) in
XL_ROUTINE from XLogReaderState.  It only has "cleanup" callback
instead.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From fd04ff06de3ab7bcc36f0c80fff42452e49e0259 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v10 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 281 ++--
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  21 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  25 ++-
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 222 insertions(+), 153 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index ca09d81b08..da468598e4 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -909,7 +909,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4329,7 +4329,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -11854,7 +11853,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11913,7 +11912,8 @@ retry:
 			readLen = 0;
 			readSource = XLOG_FROM_ANY;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -12008,7 +12008,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -12022,8 +12023,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 5995798b58..399bad0603 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -36,8 +36,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
 static void XLogReaderInvalReadState(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
@@ -274,7 +274,6 @@ XLogReadRecord(XLogReaderState *state, char **errormsg)
 	uint32		targetRecOff;
 	uint32		pageHeaderSize;
 	bool		gotheader;
-	int			

Re: Remove page-read callback from XLogReaderState.

2020-04-21 Thread Kyotaro Horiguchi
At Tue, 21 Apr 2020 17:04:27 +0900 (JST), Kyotaro Horiguchi 
 wrote in 
>

Mmm. The message body seems disappearing for uncertain reason.

cd12323440 conflicts with this. Rebased.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From b3b780c2143ae70b82fb1e8256e771f11276af31 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v9 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 278 ++--
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  21 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  23 +-
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 218 insertions(+), 152 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 11e32733c4..b0ad9376d6 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -908,7 +908,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4328,7 +4328,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -11810,7 +11809,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11869,7 +11868,8 @@ retry:
 			readLen = 0;
 			readSource = XLOG_FROM_ANY;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -11964,7 +11964,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11978,8 +11979,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 79ff976474..6250093dd9 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -36,8 +36,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
 static void XLogReaderInvalReadState(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
@@ -272,7 +272,6 @@ XLogReadRecord(XLogReaderState *state, char **errormsg)
 	uint32		targetRecOff;
 	uint32		pageHeaderSize;
 	bool		gotheader;
-	int			readOff;
 
 	/*
 	 * randAccess indicates whether to verify the previous-record pointer of
@@ -322,14 +321,20 @@ XLogReadRecord(XLogReaderState *state, char **errormsg)
 	 * byte to cover the whole record header, or at 

Re: Remove page-read callback from XLogReaderState.

2020-04-21 Thread Kyotaro Horiguchi
I found this conficts with a7e8ece41cf7a96d8a9c4c037cdfef304d950831.
Rebased on it.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From e67149578c750977a2a2872d3f4dbb3a86c82a6d Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v8 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 278 ++--
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  21 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  23 +-
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 218 insertions(+), 152 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 11e32733c4..b0ad9376d6 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -908,7 +908,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4328,7 +4328,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -11810,7 +11809,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11869,7 +11868,8 @@ retry:
 			readLen = 0;
 			readSource = XLOG_FROM_ANY;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -11964,7 +11964,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11978,8 +11979,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 79ff976474..6250093dd9 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -36,8 +36,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
 static void XLogReaderInvalReadState(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
@@ -272,7 +272,6 @@ XLogReadRecord(XLogReaderState *state, char **errormsg)
 	uint32		targetRecOff;
 	uint32		pageHeaderSize;
 	bool		gotheader;
-	int			readOff;
 
 	/*
 	 * randAccess indicates whether to verify the previous-record pointer of
@@ -322,14 +321,20 @@ XLogReadRecord(XLogReaderState *state, 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, 

Re: Remove page-read callback from XLogReaderState.

2020-03-24 Thread Kyotaro Horiguchi
5d0c2d5eba shot out this.

Rebased.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 6837855f0c938b5e34039897158bc912c6619d2b Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v7 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c   |  16 +-
 src/backend/access/transam/xlogreader.c | 272 ++--
 src/backend/access/transam/xlogutils.c  |  12 +-
 src/backend/replication/walsender.c |  10 +-
 src/bin/pg_rewind/parsexlog.c   |  16 +-
 src/bin/pg_waldump/pg_waldump.c |   8 +-
 src/include/access/xlogreader.h |  23 +-
 src/include/access/xlogutils.h  |   2 +-
 8 files changed, 211 insertions(+), 148 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 7621fc05e2..51c409d00e 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -900,7 +900,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 XLogSource source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4285,7 +4285,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -11660,7 +11659,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11719,7 +11718,8 @@ retry:
 			readLen = 0;
 			readSource = XLOG_FROM_ANY;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -11814,7 +11814,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11828,8 +11829,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 32f02256ed..2c1500443e 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -36,8 +36,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
 static void XLogReaderInvalReadState(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
@@ -269,7 +269,6 @@ XLogReadRecord(XLogReaderState *state, char **errormsg)
 	uint32		targetRecOff;
 	uint32		pageHeaderSize;
 	bool		gotheader;
-	int			readOff;
 
 	/*
 	 * randAccess indicates whether to verify the previous-record pointer of
@@ -319,14 +318,20 @@ XLogReadRecord(XLogReaderState *state, 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,
-			   Min(targetRecOff + 

Re: Remove page-read callback from XLogReaderState.

2020-01-28 Thread Kyotaro Horiguchi
At Tue, 21 Jan 2020 19:45:10 +0900 (JST), Kyotaro Horiguchi 
 wrote in 
> Hello.
> 
> At Mon, 20 Jan 2020 17:24:07 +0900 (JST), Kyotaro Horiguchi 
>  wrote in 
> > Separating XLogBeginRead seems reasonable.  The annoying recptr trick
> > is no longer needed. In particular some logical-decoding stuff become
> > far cleaner by the patch.
> > 
> > fetching_ckpt of ReadRecord is a bit annoying but that coundn't be
> > moved outside to, say, ReadCheckpointRecord in a clean way. (Anyway
> > XLogBeginRead is not the place, of course).
> > 
> > As I looked through it, it looks good to me but give me some more time
> > to look closer.
> 
> It seems to me that it works perfectly, and everything looks good to
> me except one point.
> 
> -  * In this case, the passed-in record pointer should already be
> +  * In this case, EndRecPtr record pointer should already be
> 
> I'm not confident but isn't the "record pointer" redundant?  EndRecPtr
> seems containing that meaning, and the other occurances of that kind
> of variable names are not accompanied by that.

I rebased this on the 38a957316d and its follow-on patch 30012a04a6.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 2c605922be988292a80a479b4e59cf799299db19 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v13 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c |  16 +-
 src/backend/access/transam/xlogreader.c   | 282 ++
 src/backend/access/transam/xlogutils.c|  12 +-
 .../replication/logical/logicalfuncs.c|   2 +-
 src/backend/replication/walsender.c   |  10 +-
 src/bin/pg_rewind/parsexlog.c |  16 +-
 src/bin/pg_waldump/pg_waldump.c   |   8 +-
 src/include/access/xlogreader.h   |  23 +-
 src/include/access/xlogutils.h|   2 +-
 src/include/replication/logicalfuncs.h|   2 +-
 10 files changed, 218 insertions(+), 155 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 6e09ded597..357432ffa2 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -883,7 +883,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 int source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4262,7 +4262,6 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
@@ -11586,7 +11585,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11645,7 +11644,8 @@ retry:
 			readLen = 0;
 			readSource = 0;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -11740,7 +11740,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11754,8 +11755,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 

Re: Remove page-read callback from XLogReaderState.

2020-01-26 Thread Heikki Linnakangas

On 21/01/2020 13:33, Craig Ringer wrote:

On Tue, 21 Jan 2020 at 18:46, Kyotaro Horiguchi  wrote:

It seems to me that it works perfectly, and everything looks good


I seem to remember some considerable pain in this area when it came to
timeline switches. Especially with logical decoding and xlog records
that split across a segment boundary.

My first attempts at logical decoding timeline following appeared fine
and passed tests until they were put under extended real world
workloads, at which point they exploded when they tripped corner cases
like this.

I landed up writing ridiculous regression tests to trigger some of
these behaviours. I don't recall how many of them made it into the
final patch to core but it's worth a look in the TAP test suite.


Yeah, the timeline switching stuff is complicated. The small 
XLogBeginRead() patch isn't really affected, but it's definitely 
something to watch out for in the callback API patch. If you happen to 
have any extra ridiculous tests still lying around, would be nice to 
look at them.


- Heikki




Re: Remove page-read callback from XLogReaderState.

2020-01-26 Thread Heikki Linnakangas

On 21/01/2020 12:45, Kyotaro Horiguchi wrote:

At Mon, 20 Jan 2020 17:24:07 +0900 (JST), Kyotaro Horiguchi 
 wrote in

Separating XLogBeginRead seems reasonable.  The annoying recptr trick
is no longer needed. In particular some logical-decoding stuff become
far cleaner by the patch.

fetching_ckpt of ReadRecord is a bit annoying but that coundn't be
moved outside to, say, ReadCheckpointRecord in a clean way. (Anyway
XLogBeginRead is not the place, of course).

As I looked through it, it looks good to me but give me some more time
to look closer.


It seems to me that it works perfectly, and everything looks good to
me except one point.

-* In this case, the passed-in record pointer should already be
+* In this case, EndRecPtr record pointer should already be

I'm not confident but isn't the "record pointer" redundant?  EndRecPtr
seems containing that meaning, and the other occurances of that kind
of variable names are not accompanied by that.


I fixed that, fixed the XLogFindNextRecord() function so that it 
positions the reader like XLogBeginRead() does (I had already adjusted 
the comments to say that, but the function didn't actually do it), and 
pushed. Thanks for the review!


I'll continue looking at the callback API changes on Monday.

- Heikki




Re: Remove page-read callback from XLogReaderState.

2020-01-21 Thread Craig Ringer
On Tue, 21 Jan 2020 at 18:46, Kyotaro Horiguchi  wrote:
>
> Hello.
>
> At Mon, 20 Jan 2020 17:24:07 +0900 (JST), Kyotaro Horiguchi 
>  wrote in
> > Separating XLogBeginRead seems reasonable.  The annoying recptr trick
> > is no longer needed. In particular some logical-decoding stuff become
> > far cleaner by the patch.
> >
> > fetching_ckpt of ReadRecord is a bit annoying but that coundn't be
> > moved outside to, say, ReadCheckpointRecord in a clean way. (Anyway
> > XLogBeginRead is not the place, of course).
> >
> > As I looked through it, it looks good to me but give me some more time
> > to look closer.
>
> It seems to me that it works perfectly, and everything looks good

I seem to remember some considerable pain in this area when it came to
timeline switches. Especially with logical decoding and xlog records
that split across a segment boundary.

My first attempts at logical decoding timeline following appeared fine
and passed tests until they were put under extended real world
workloads, at which point they exploded when they tripped corner cases
like this.

I landed up writing ridiculous regression tests to trigger some of
these behaviours. I don't recall how many of them made it into the
final patch to core but it's worth a look in the TAP test suite.

-- 
 Craig Ringer   http://www.2ndQuadrant.com/
 2ndQuadrant - PostgreSQL Solutions for the Enterprise




Re: Remove page-read callback from XLogReaderState.

2020-01-21 Thread Kyotaro Horiguchi
Hello.

At Mon, 20 Jan 2020 17:24:07 +0900 (JST), Kyotaro Horiguchi 
 wrote in 
> Separating XLogBeginRead seems reasonable.  The annoying recptr trick
> is no longer needed. In particular some logical-decoding stuff become
> far cleaner by the patch.
> 
> fetching_ckpt of ReadRecord is a bit annoying but that coundn't be
> moved outside to, say, ReadCheckpointRecord in a clean way. (Anyway
> XLogBeginRead is not the place, of course).
> 
> As I looked through it, it looks good to me but give me some more time
> to look closer.

It seems to me that it works perfectly, and everything looks good to
me except one point.

-* In this case, the passed-in record pointer should already be
+* In this case, EndRecPtr record pointer should already be

I'm not confident but isn't the "record pointer" redundant?  EndRecPtr
seems containing that meaning, and the other occurances of that kind
of variable names are not accompanied by that.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2020-01-20 Thread Kyotaro Horiguchi
Thanks!

At Fri, 17 Jan 2020 20:14:36 +0200, Heikki Linnakangas  wrote 
in 
> On 29/11/2019 10:14, Kyotaro Horiguchi wrote:
> > At Thu, 28 Nov 2019 21:37:03 +0900 (JST), Kyotaro Horiguchi
> >  wrote in
>  0dc8ead463 hit this. Rebased.
> >>>
> >>> Please review the pg_waldump.c hunks in 0001; they revert recent
> >>> changes.
> >>
> >> Ughhh! I'l check it. Thank you for noticing!!
> > Fixed that, re-rebased and small comment and cosmetic changes in this
> > version.
> 
> Thanks! I finally got around to look at this again. A lot has happened
> since I last looked at this. Notably, commit 0dc8ead463 introduced
> another callback function into the XLogReader interface. It's not
> entirely clear what the big picture with the new callback was and how
> that interacts with the refactoring here. I'll have to spend some time
> to make myself familiar with those changes.
> 
> Earlier in this thread, you wrote:
> > - Changed calling convention of XLogReadRecord
> > To make caller loop simple, XLogReadRecord now allows to specify
> > the same valid value while reading the a record. No longer need
> > to change lsn to invalid after the first call in the following
> > reader loop.
> >while (XLogReadRecord(state, lsn, , ) ==
> >XLREAD_NEED_DATA)
> >{
> >  if (!page_reader(state))
> >break;
> >}
> 
> Actually, I had also made a similar change in the patch version I
> posted at
> https://www.postgresql.org/message-id/4f7a5fad-fa04-b0a3-231b-56d200b646dc%40iki.fi.
>  Maybe
> you missed that email? It looks like you didn't include any of the
> changes from that in the patch series. In any case, clearly that idea
> has some merit, since we both independently made a change in that
> calling convention :-).

I'm very sorry but I missed that...

> Actually, I propose that we make that change first, and then continue
> reviewing the rest of these patches. I think it's a more convenient
> interface, independently of the callback refactoring. What do you
> think of the attached patch?

Separating XLogBeginRead seems reasonable.  The annoying recptr trick
is no longer needed. In particular some logical-decoding stuff become
far cleaner by the patch.

fetching_ckpt of ReadRecord is a bit annoying but that coundn't be
moved outside to, say, ReadCheckpointRecord in a clean way. (Anyway
XLogBeginRead is not the place, of course).

As I looked through it, it looks good to me but give me some more time
to look closer.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2020-01-17 Thread Alvaro Herrera
On 2020-Jan-17, Heikki Linnakangas wrote:

> I changed that by adding new function, XLogBeginRead(), that repositions the
> reader, and removed the 'lsn' argument from XLogReadRecord() altogether. All
> callers except one in findLastCheckPoint() pg_rewind.c positioned the reader
> once, and then just read sequentially from there, so I think that API is
> more convenient.

I like it.  +1

-- 
Álvaro Herrerahttps://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services




Re: Remove page-read callback from XLogReaderState.

2020-01-17 Thread Heikki Linnakangas

On 29/11/2019 10:14, Kyotaro Horiguchi wrote:

At Thu, 28 Nov 2019 21:37:03 +0900 (JST), Kyotaro Horiguchi 
 wrote in

0dc8ead463 hit this. Rebased.


Please review the pg_waldump.c hunks in 0001; they revert recent changes.


Ughhh! I'l check it. Thank you for noticing!!


Fixed that, re-rebased and small comment and cosmetic changes in this
version.


Thanks! I finally got around to look at this again. A lot has happened 
since I last looked at this. Notably, commit 0dc8ead463 introduced 
another callback function into the XLogReader interface. It's not 
entirely clear what the big picture with the new callback was and how 
that interacts with the refactoring here. I'll have to spend some time 
to make myself familiar with those changes.


Earlier in this thread, you wrote:


- Changed calling convention of XLogReadRecord

To make caller loop simple, XLogReadRecord now allows to specify
the same valid value while reading the a record. No longer need
to change lsn to invalid after the first call in the following
reader loop.

   while (XLogReadRecord(state, lsn, , ) == XLREAD_NEED_DATA)
   {
 if (!page_reader(state))
   break;
   }


Actually, I had also made a similar change in the patch version I posted 
at 
https://www.postgresql.org/message-id/4f7a5fad-fa04-b0a3-231b-56d200b646dc%40iki.fi. 
Maybe you missed that email? It looks like you didn't include any of the 
changes from that in the patch series. In any case, clearly that idea 
has some merit, since we both independently made a change in that 
calling convention :-).


I changed that by adding new function, XLogBeginRead(), that repositions 
the reader, and removed the 'lsn' argument from XLogReadRecord() 
altogether. All callers except one in findLastCheckPoint() pg_rewind.c 
positioned the reader once, and then just read sequentially from there, 
so I think that API is more convenient. With that, the usage looks 
something like this:


state = XLogReaderAllocate (...)
XLogBeginRead(state, start_lsn);
while (ctx->reader->EndRecPtr < end_of_wal)
{
while (XLogReadRecord(state, , ) == XLREAD_NEED_DATA)
{
if (!page_reader(state))
break;
}
/* do stuff */

}

Actually, I propose that we make that change first, and then continue 
reviewing the rest of these patches. I think it's a more convenient 
interface, independently of the callback refactoring. What do you think 
of the attached patch?


- Heikki
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6f7ee0c947d..5adf956f413 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1338,7 +1338,8 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
  errmsg("out of memory"),
  errdetail("Failed while allocating a WAL reading processor.")));
 
-	record = XLogReadRecord(xlogreader, lsn, );
+	XLogBeginRead(xlogreader, lsn);
+	record = XLogReadRecord(xlogreader, );
 	if (record == NULL)
 		ereport(ERROR,
 (errcode_for_file_access(),
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 7f4f784c0eb..882d5e8a73f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -897,7 +897,7 @@ static void UpdateLastRemovedPtr(char *filename);
 static void ValidateXLOGDirectoryStructure(void);
 static void CleanupBackupHistory(void);
 static void UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force);
-static XLogRecord *ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr,
+static XLogRecord *ReadRecord(XLogReaderState *xlogreader,
 			  int emode, bool fetching_ckpt);
 static void CheckRecoveryConsistency(void);
 static XLogRecord *ReadCheckpointRecord(XLogReaderState *xlogreader,
@@ -4246,17 +4246,17 @@ CleanupBackupHistory(void)
 }
 
 /*
- * Attempt to read an XLOG record.
+ * Attempt to read the next XLOG record.
  *
- * If RecPtr is valid, try to read a record at that position.  Otherwise
- * try to read a record just after the last one previously read.
+ * Before first call, the reader needs to be positioned to the first record
+ * by calling XLogBeginRead().
  *
  * If no valid record is available, returns NULL, or fails if emode is PANIC.
  * (emode must be either PANIC, LOG). In standby mode, retries until a valid
  * record is available.
  */
 static XLogRecord *
-ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
+ReadRecord(XLogReaderState *xlogreader, int emode,
 		   bool fetching_ckpt)
 {
 	XLogRecord *record;
@@ -4265,7 +4265,7 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
-	private->randAccess = (RecPtr != InvalidXLogRecPtr);
+	private->randAccess = (xlogreader->ReadRecPtr != InvalidXLogRecPtr);
 
 	/* This is the first attempt to read this page. */
 	lastSourceFailed = false;
@@ -4274,7 +4274,7 @@ 

Re: Remove page-read callback from XLogReaderState.

2019-11-29 Thread Kyotaro Horiguchi
At Thu, 28 Nov 2019 21:37:03 +0900 (JST), Kyotaro Horiguchi 
 wrote in 
> > > 0dc8ead463 hit this. Rebased.
> > 
> > Please review the pg_waldump.c hunks in 0001; they revert recent changes.
> 
> Ughhh! I'l check it. Thank you for noticing!!

Fixed that, re-rebased and small comment and cosmetic changes in this
version.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 27d9a619bb23cc3175658e34e2fec01eb545b40f Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v12 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c |  16 +-
 src/backend/access/transam/xlogreader.c   | 272 ++
 src/backend/access/transam/xlogutils.c|  12 +-
 .../replication/logical/logicalfuncs.c|   2 +-
 src/backend/replication/walsender.c   |  10 +-
 src/bin/pg_rewind/parsexlog.c |  16 +-
 src/bin/pg_waldump/pg_waldump.c   |   8 +-
 src/include/access/xlogreader.h   |  23 +-
 src/include/access/xlogutils.h|   2 +-
 src/include/replication/logicalfuncs.h|   2 +-
 10 files changed, 213 insertions(+), 150 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 5f0ee50092..4a6bd6e002 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -884,7 +884,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 int source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4249,7 +4249,6 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (RecPtr != InvalidXLogRecPtr);
@@ -11537,7 +11536,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11596,7 +11595,8 @@ retry:
 			readLen = 0;
 			readSource = 0;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -11691,7 +11691,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11705,8 +11706,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 67418b05f1..063223701e 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -36,8 +36,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
 static void XLogReaderInvalReadState(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
@@ -245,7 +245,6 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 	

Re: Remove page-read callback from XLogReaderState.

2019-11-28 Thread Kyotaro Horiguchi
At Wed, 27 Nov 2019 01:11:40 -0300, Alvaro Herrera  
wrote in 
> On 2019-Nov-27, Kyotaro Horiguchi wrote:
> 
> > At Thu, 24 Oct 2019 14:51:01 +0900 (JST), Kyotaro Horiguchi 
> >  wrote in 
> > > Rebased.
> > 
> > 0dc8ead463 hit this. Rebased.
> 
> Please review the pg_waldump.c hunks in 0001; they revert recent changes.

Ughhh! I'l check it. Thank you for noticing!!

At Wed, 27 Nov 2019 12:57:47 +0900, Michael Paquier  wrote 
in 
> Note: Moved to next CF.

Thanks.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2019-11-26 Thread Alvaro Herrera
On 2019-Nov-27, Kyotaro Horiguchi wrote:

> At Thu, 24 Oct 2019 14:51:01 +0900 (JST), Kyotaro Horiguchi 
>  wrote in 
> > Rebased.
> 
> 0dc8ead463 hit this. Rebased.

Please review the pg_waldump.c hunks in 0001; they revert recent changes.


-- 
Álvaro Herrerahttps://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services




Re: Remove page-read callback from XLogReaderState.

2019-11-26 Thread Michael Paquier
On Wed, Nov 27, 2019 at 12:09:23PM +0900, Kyotaro Horiguchi wrote:
> 0dc8ead463 hit this. Rebased.

Note: Moved to next CF.
--
Michael


signature.asc
Description: PGP signature


Re: Remove page-read callback from XLogReaderState.

2019-11-26 Thread Kyotaro Horiguchi
At Thu, 24 Oct 2019 14:51:01 +0900 (JST), Kyotaro Horiguchi 
 wrote in 
> Rebased.

0dc8ead463 hit this. Rebased.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From d9007aee88f7400b0f03ced1b80584964a1b0b79 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v11 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c |  16 +-
 src/backend/access/transam/xlogreader.c   | 272 ++
 src/backend/access/transam/xlogutils.c|  12 +-
 .../replication/logical/logicalfuncs.c|   2 +-
 src/backend/replication/walsender.c   |  10 +-
 src/bin/pg_rewind/parsexlog.c |  16 +-
 src/bin/pg_waldump/pg_waldump.c   |  14 +-
 src/include/access/xlogreader.h   |  23 +-
 src/include/access/xlogutils.h|   2 +-
 src/include/replication/logicalfuncs.h|   2 +-
 10 files changed, 216 insertions(+), 153 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 5f0ee50092..4a6bd6e002 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -884,7 +884,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 int source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4249,7 +4249,6 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (RecPtr != InvalidXLogRecPtr);
@@ -11537,7 +11536,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11596,7 +11595,8 @@ retry:
 			readLen = 0;
 			readSource = 0;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -11691,7 +11691,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11705,8 +11706,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 67418b05f1..388662ade4 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -36,8 +36,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
 static void XLogReaderInvalReadState(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
@@ -245,7 +245,6 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 	uint32		targetRecOff;
 	uint32		pageHeaderSize;
 	bool		gotheader;
-	int			readOff;
 
 	/*
 	 * randAccess indicates whether to verify the previous-record pointer of
@@ -297,14 +296,20 @@ 

Re: Remove page-read callback from XLogReaderState.

2019-10-23 Thread Kyotaro Horiguchi
Rebased.

I intentionally left duplicate code in XLogNeedData but changed my
mind to remove it. It makes the function small and clearer.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 7c4ce152d248546c8f56057febae6b17b6fa71bb Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v9 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c |  16 +-
 src/backend/access/transam/xlogreader.c   | 273 ++
 src/backend/access/transam/xlogutils.c|  10 +-
 .../replication/logical/logicalfuncs.c|   2 +-
 src/backend/replication/walsender.c   |  10 +-
 src/bin/pg_rewind/parsexlog.c |  16 +-
 src/bin/pg_waldump/pg_waldump.c   |   8 +-
 src/include/access/xlogreader.h   |  23 +-
 src/include/access/xlogutils.h|   2 +-
 src/include/replication/logicalfuncs.h|   2 +-
 src/test/recovery/t/011_crash_recovery.pl |   1 +
 11 files changed, 213 insertions(+), 150 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b602e28f61..a7630c643a 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -884,7 +884,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 int source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4249,7 +4249,6 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (RecPtr != InvalidXLogRecPtr);
@@ -11540,7 +11539,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11599,7 +11598,8 @@ retry:
 			readLen = 0;
 			readSource = 0;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -11694,7 +11694,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11708,8 +11709,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index c8b0d2303d..66f3bc5597 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -34,8 +34,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
 static void XLogReaderInvalReadState(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
@@ -244,7 +244,6 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 	uint32		targetRecOff;
 	uint32		pageHeaderSize;
 	bool		gotheader;
-	int			readOff;
 
 	/*
 	 * randAccess indicates whether to 

Re: Remove page-read callback from XLogReaderState.

2019-09-26 Thread Kyotaro Horiguchi
At Wed, 25 Sep 2019 15:50:32 +0900 (Tokyo Standard Time), Kyotaro Horiguchi 
 wrote in 
<20190925.155032.13779064.horikyota@gmail.com>
> 709d003fbd hit this. Rebased.

Oops! I found a silly silent bug that it doesn't verify the first
page in new segments. Moreover it didin't load the first page in
a new loaded segment.


- Fixed a bug that it didn't load the first segment once new
  loaded segment is loaded.

- Fixed a bug that it didn't verify the first segment if it is
  not the target page.

Some fishy codes are reaminig but I'll post once the fixed
version.

regares.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From d511d7b9db24450596c82973a380fbae3b2d6ea1 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v8 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c  |  16 +-
 src/backend/access/transam/xlogreader.c| 306 +++--
 src/backend/access/transam/xlogutils.c |  10 +-
 src/backend/replication/logical/logicalfuncs.c |   2 +-
 src/backend/replication/walsender.c|  10 +-
 src/bin/pg_rewind/parsexlog.c  |  16 +-
 src/bin/pg_waldump/pg_waldump.c|   8 +-
 src/include/access/xlogreader.h|  23 +-
 src/include/access/xlogutils.h |   2 +-
 src/include/replication/logicalfuncs.h |   2 +-
 src/test/recovery/t/011_crash_recovery.pl  |   1 +
 11 files changed, 239 insertions(+), 157 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 6c69eb6dd7..5dcb2e500c 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -884,7 +884,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 int source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4249,7 +4249,6 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (RecPtr != InvalidXLogRecPtr);
@@ -11522,7 +11521,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11581,7 +11580,8 @@ retry:
 			readLen = 0;
 			readSource = 0;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -11676,7 +11676,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11690,8 +11691,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 27c27303d6..900a628752 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -34,8 +34,8 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool 

Re: Remove page-read callback from XLogReaderState.

2019-09-25 Thread Kyotaro Horiguchi
Hello.

709d003fbd hit this. Rebased.

Works fine but needs detailed verification and maybe further
cosmetic fixes.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 6be22b10c9df068c53c98ad3106e1bd88e07aeeb Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v7 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c  |  16 +-
 src/backend/access/transam/xlogreader.c| 332 +++--
 src/backend/access/transam/xlogutils.c |  10 +-
 src/backend/replication/logical/logicalfuncs.c |   2 +-
 src/backend/replication/walsender.c|  10 +-
 src/bin/pg_rewind/parsexlog.c  |  16 +-
 src/bin/pg_waldump/pg_waldump.c|   8 +-
 src/include/access/xlogreader.h|  23 +-
 src/include/access/xlogutils.h |   2 +-
 src/include/replication/logicalfuncs.h |   2 +-
 10 files changed, 259 insertions(+), 162 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 6c69eb6dd7..5dcb2e500c 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -884,7 +884,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 int source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 		bool fetching_ckpt, XLogRecPtr tliRecPtr);
@@ -4249,7 +4249,6 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (RecPtr != InvalidXLogRecPtr);
@@ -11522,7 +11521,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf)
 {
@@ -11581,7 +11580,8 @@ retry:
 			readLen = 0;
 			readSource = 0;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return false;
 		}
 	}
 
@@ -11676,7 +11676,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return true;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11690,8 +11691,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return false;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 27c27303d6..c2bb664f07 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -34,9 +34,9 @@
 static void report_invalid_record(XLogReaderState *state, const char *fmt,...)
 			pg_attribute_printf(2, 3);
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
-static int	ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr,
-			 int reqLen);
-static void XLogReaderInvalReadState(XLogReaderState *state);
+static bool XLogNeedData(XLogReaderState *state, XLogRecPtr pageptr,
+		 int reqLen, bool header_inclusive);
+static void XLogReaderDiscardReadingPage(XLogReaderState *state);
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
 static bool ValidXLogRecord(XLogReaderState *state, XLogRecord *record,
@@ -104,7 +104,7 @@ XLogReaderAllocate(int wal_segment_size, const char *waldir,
 	/* system_identifier initialized to zeroes above */
 	

Re: Remove page-read callback from XLogReaderState.

2019-09-10 Thread Kyotaro Horiguchi
Attached is new version:

- Rebased. Cleaned up

- Rebased to the current master

- Fixed a known bug in the first step patch. It caused
  timeline-following failure on a standby of a promoted primary.

- Fixed confused naming and setting of the parameter
  includes_paeg_header.

- Removed useless XLogNeedData call in
  XLREAD_NEED_CONTINUATION. The first call to the function
  ensures that all required data is loaded. Finally, every case
  block has just one XLogNeedData call.

- Removed the label "again" in XLogReadRecord. It is now needed
  only to repeat XLREAD_NEED_CONTINUATION state. It is naturally
  writtable as a while loop.

- Ensure record == NULL when XLogReadRecord returns other than
  XLREAD_SUCCESS. Previously the value was not changed in that
  case and it was not intuitive behavior for callers.

- Renamed XLREAD_NEED_* to XLREAD_*.

- Removed global variables readOff, readLen, readSegNo. (0003)

  Other similar variables like readFile/readSource are left alone
  as they are not common states of page reader and not in
  XLogReaderState.


The attched are the current status, it is separated to two
significant parts plus one for readability.

v6-0001-Move-callback-call-from-ReadPageInternal-to-XLogR.patch:

  ReadPageInternal part of the patch. Moves callback calls from
  ReadPageInternal up to XLogReadRecord. Rerorded commit message
  and fixed the bug in v5.

v6-0002-Move-page-reader-out-of-XLogReadRecord.patch

  The remaining part of the main work. Eliminates callback calls
  from XLogReadRecord. Reworded commit message and fixed several
  bugs.

v6-0003-Remove-globals-readSegNo-readOff-readLen.patch

  Seprate patch to remove some globals that are duplicate with
  members of XLogReaderState.

v6-0004-Change-policy-of-XLog-read-buffer-allocation.patch

  Separate patch to move page buffer allocation from
  XLogReaderAllocation from allers of XLogReadRecord.


regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 81d3e58a1f017f34bb654cc4f66a4b9646469349 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v6 1/4] Move callback-call from ReadPageInternal to
 XLogReadRecord.

The current WAL record reader reads page data using a call back
function.  Although it is not so problematic alone, it would be a
problem if we are going to do add tasks like encryption which is
performed on page data before WAL reader reads them. To avoid that the
record reader facility has to have a new code path corresponds to
every new callback, this patch separates page reader from WAL record
reading facility by modifying the current WAL record reader to a state
machine.

As the first step of that change, this patch moves the page reader
function out of ReadPageInternal, then the remaining tasks of the
function are taken over by the new function XLogNeedData. As the
result XLogPageRead directly calls the page reader callback function
according to the feedback from XLogNeedData.
---
 src/backend/access/transam/xlog.c  |  16 +-
 src/backend/access/transam/xlogreader.c| 336 +++--
 src/backend/access/transam/xlogutils.c |  10 +-
 src/backend/replication/logical/logicalfuncs.c |   4 +-
 src/backend/replication/walsender.c|  10 +-
 src/bin/pg_rewind/parsexlog.c  |  17 +-
 src/bin/pg_waldump/pg_waldump.c|   8 +-
 src/include/access/xlogreader.h|  26 +-
 src/include/access/xlogutils.h |   2 +-
 src/include/replication/logicalfuncs.h |   2 +-
 10 files changed, 265 insertions(+), 166 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 6876537b62..d7f899e738 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -884,7 +884,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 int source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static bool	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf,
 		 TimeLineID *readTLI);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
@@ -4249,7 +4249,6 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 	XLogRecord *record;
 	XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
 
-	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
 	private->randAccess = (RecPtr != InvalidXLogRecPtr);
@@ -11521,7 +11520,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static bool
 

Re: Remove page-read callback from XLogReaderState.

2019-09-06 Thread Kyotaro Horiguchi
At Thu, 22 Aug 2019 10:43:52 +0900 (Tokyo Standard Time), Kyotaro Horiguchi 
 wrote in 
<20190822.104352.26342272.horikyota@gmail.com>
> I think you diff is intelligible enough for me. I'll take this if
> you haven't done. Anyway I'm staring on this.


- Reducing state variables

It was a problem for me that there seems to be many state
variables than required. So first I tried to reduce them.

Now readPagePtr and readLen are used bidirectionally.
XLogNeedData sets it as request and page reader set readLen to
the actual length.  Similarly verified* changes only when page
header is verified, so I introduced page_verified instead of the
variables.


- Changed calling convention of XLogReadRecord

To make caller loop simple, XLogReadRecord now allows to specify
the same valid value while reading the a record. No longer need
to change lsn to invalid after the first call in the following
reader loop.

   while (XLogReadRecord(state, lsn, , ) == XLREAD_NEED_DATA)
   {
 if (!page_reader(state))
   break;
   }

- Frequent data request caused by seeing long page header.

XLogNeedData now takes the fourth parameter includes_page_header.
True means the caller is requesting with reqLen that is not
counting page header length. But it makes the function a bit too
complex than expected.  Blindly requsting anticipating long page
header for a new page may prevent page-reader from returning the
bytes already at hand by waiting for bytes that won't come.  To
prevent such a case the funtion should request anticipating short
page header first for a new page, then make a re-request using
SizeOfLongPHD if needed. Of course it is unlikely to happen for
file sources, and unlikely to harm physical replication (and the
behavior is not changed).  Finally, the outcome is more or less
the same with just stashing the seemingly bogus retry from
XLogReadRecord to XLogNeedData.  If we are allowed to utilize the
knowlege that long page header is attached to only the first page
of a segment, such complexitly could be eliminated.


- Moving page buffer allocation

As for page buffer allocation, I'm not sure it is meaningful, as
the reader assumes the buffer is in the same with page size,
which is immutable system-wide. It would be surely meanintful if
it were on the caller to decide its own block size, or loading
unit. Anyway it is in the third patch.

- Restored early check-out of record header

The current record reader code seems to be designed to bail-out
by broken record header as earlier as possible, perhaps in order
to prevent impossible size of read in. So I restored the
behavior.



The attched are the current status, it is separated to two
significant parts plus one for readability.

v5-0001-Move-callback-call-from-ReadPageInternal-to-XLogR.patch:

  ReadPageInternal part of the patch. Moves callback calls from
  ReadPageInternal up to XLogReadRecord.  Some of recovery tests
  fail applyin only this one but I don't want to put more efforts
  to make this state perfecgt.

v5-0002-Move-page-reader-out-of-XLogReadRecord.patch

  The remaining part of the main work. Eliminates callback calls
  from XLogReadRecord. Applies to current master.  Passes all
  regression and TAP tests.

v5-0003-Change-policy-of-XLog-read-buffer-allocation.patch

  Separate patch to move page buffer allocation from
  XLogReaderAllocation from allers of XLogReadRecord.


regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center

>From 067c3bbb9105c391b7c19cc9602a5df6db5fb434 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 5 Sep 2019 20:21:55 +0900
Subject: [PATCH v5 1/3] Move callback-call from ReadPageInternal to
 XLogReadRecord.

WAL reader facility used to call given page-reader callback function
in the ReadPageInternal, which is two levels below from
ReadRecord. That makes things a bit complex, but furthermore we are
going to have additional callbacks for encryption, compression or
something like that works before or after reading pages. Just adding
them as new callback makes things messier. If the caller of the
current ReadRecord could call page fetching function directly, things
would get quite easier.

As the first step of that change, this patch moves the place where
that callbacks are called by 1 level above
ReadPageInternal. XLogPageRead uses a loop over new function
XLogNeedData and the callback directly instead of ReadPageInternal.
---
 src/backend/access/transam/xlog.c  |  15 +-
 src/backend/access/transam/xlogreader.c| 355 -
 src/backend/access/transam/xlogutils.c |  10 +-
 src/backend/replication/logical/logicalfuncs.c |   4 +-
 src/backend/replication/walsender.c|  10 +-
 src/bin/pg_rewind/parsexlog.c  |  17 +-
 src/bin/pg_waldump/pg_waldump.c|   8 +-
 src/include/access/xlogreader.h|  30 ++-
 src/include/access/xlogutils.h |   2 +-
 src/include/replication/logicalfuncs.h |   2 +-

Re: Remove page-read callback from XLogReaderState.

2019-08-22 Thread Heikki Linnakangas

On 22/08/2019 04:43, Kyotaro Horiguchi wrote:

At Mon, 29 Jul 2019 22:39:57 +0300, Heikki Linnakangas  wrote in 


On 12/07/2019 10:10, Kyotaro Horiguchi wrote:
* XLogReaderState->readBuf is now allocated and controlled by the
* caller, not by xlogreader.c itself. When XLogReadRecord() needs data,
* the caller makes the data available in readBuf, which can point to the
* same buffer in all calls, or the caller may allocate a new buffer, or
* it may point to a part of a larger buffer, whatever is convenient for
* the caller. (Currently, all callers just allocate a BLCKSZ'd buffer,
* though). The caller also sets readPagPtr, readLen and readPageTLI to
* tell XLogReadRecord() what's in the buffer. So all these read* fields
* are now set by the caller, XLogReadRecord() only reads them.


The caller knows how many byes to be read. So the caller provides
the required buffer seems reasonable.


I also had in mind that the caller could provide a larger buffer, 
spanning multiple pages, in one XLogReadRecord() call. It might be 
convenient to load a whole WAL file in memory and pass it to 
XLogReadRecord() in one call, for example. I think the interface would 
now allow that, but the code won't actually take advantage of that. 
XLogReadRecord() will always ask for one page at a time, and I think it 
will ask the caller for more data between each page, even if the caller 
supplies more than one page in one call.



I'm not sure how intelligible this patch is in its current state. But
I think the general idea is good. I plan to clean it up further next
week, but feel free to work on it before that, either based on this
patch or by starting afresh from your patch set.


I think you diff is intelligible enough for me. I'll take this if
you haven't done. Anyway I'm staring on this.


Thanks! I did actually spend some time on this last week, but got 
distracted by something else before finishing it up and posting a patch. 
Here's a snapshot of what I have in my local branch. It seems to pass 
"make check-world", but probably needs some more cleanup.


Main changes since last version:

* I changed the interface so that there is a new function to set the 
starting position, XLogBeginRead(), and XLogReadRecord() always 
continues from where it left off. I think that's more clear than having 
a starting point argument in XLogReadRecord(), which was only set on the 
first call. It makes the calling code more clear, too, IMO.


* Refactored the implementation of XLogFindNextRecord(). 
XLogFindNextRecord() is now a sibling function of XLogBeginRead(). It 
sets the starting point like XLogBeginRead(). The difference is that 
with XLogFindNextRecord(), the starting point doesn't need to point to a 
valid record, it will "fast forward" to the next valid record after the 
point. The "fast forwarding" is done in an extra state in the state 
machine in XLogReadRecord().


* I refactored XLogReadRecord() and the internal XLogNeedData() 
function. XLogNeedData() used to contain logic for verifying segment and 
page headers. That works quite differently now. Checking the segment 
header is now a new state in the state machine, and the page header is 
verified at the top of XLogReadRecord(), whenever the caller provides 
new data. I think that makes the code in XLogReadRecord() more clear.


- Heikki
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 477709bbc23..8ecb5ea55c5 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1386,15 +1386,21 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
 	XLogReaderState *xlogreader;
 	char	   *errormsg;
 
-	xlogreader = XLogReaderAllocate(wal_segment_size, _local_xlog_page,
-	NULL);
+	xlogreader = XLogReaderAllocate(wal_segment_size);
 	if (!xlogreader)
 		ereport(ERROR,
 (errcode(ERRCODE_OUT_OF_MEMORY),
  errmsg("out of memory"),
  errdetail("Failed while allocating a WAL reading processor.")));
+	xlogreader->readBuf = palloc(XLOG_BLCKSZ);
+
+	XLogBeginRead(xlogreader, lsn);
+	while (XLogReadRecord(xlogreader, , ) ==
+		   XLREAD_NEED_DATA)
+	{
+		read_local_xlog_page(xlogreader);
+	}
 
-	record = XLogReadRecord(xlogreader, lsn, );
 	if (record == NULL)
 		ereport(ERROR,
 (errcode_for_file_access(),
@@ -1416,6 +1422,7 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
 	*buf = palloc(sizeof(char) * XLogRecGetDataLen(xlogreader));
 	memcpy(*buf, XLogRecGetData(xlogreader), sizeof(char) * XLogRecGetDataLen(xlogreader));
 
+	pfree(xlogreader->readBuf);
 	XLogReaderFree(xlogreader);
 }
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index e651a841bbe..1bb303a90dc 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -803,13 +803,6 @@ static XLogSource readSource = 0;	/* XLOG_FROM_* code */
 static XLogSource currentSource = 0;	/* XLOG_FROM_* code */
 static bool lastSourceFailed = false;
 

Re: Remove page-read callback from XLogReaderState.

2019-08-21 Thread Kyotaro Horiguchi
Thank you for the suggestion, Heikki.

At Mon, 29 Jul 2019 22:39:57 +0300, Heikki Linnakangas  wrote 
in 
> On 12/07/2019 10:10, Kyotaro Horiguchi wrote:
> >> Just FYI, to me this doesn't clearly enough look like an improvement,
> >> for a change of this size.
> > Thanks for the opiniton. I kinda agree about size but it is a
> > decision between "having multiple callbacks called under the
> > hood" vs "just calling a series of functions".  I think the
> > patched XlogReadRecord is easy to use in many situations.
> > It would be better if I could completely refactor the function
> > without the syntax tricks but I think the current patch is still
> > smaller and clearer than overhauling it.
> 
> I like the idea of refactoring XLogReadRecord() to not use a callback,
> and return a XLREAD_NEED_DATA value instead. It feels like a nicer,
> easier-to-use, interface, given that all the page-read functions need
> quite a bit of state and internal logic themselves. I remember that I
> felt that that would be a nicer interface when we originally extracted
> xlogreader.c into a reusable module, but I didn't want to make such
> big changes to XLogReadRecord() at that point.
> 
> I don't much like the "continuation" style of implementing the state
> machine. Nothing wrong with such a style in principle, but we don't do
> that anywhere else, and the macros seem like overkill, and turning the

Agreed that it's a kind of ugly. I could overhaul the logic to
reduce state variables, but I thought that it would make the
patch hardly reviewable.

The "continuation" style was intended to impact the main path's
shape as small as possible. For the same reason I made variables
static instead of using individual state struct or reducing state
variables. (And it the style was fun for me:p)

> local variables static is pretty ugly. But I think XLogReadRecord()
> could be rewritten into a more traditional state machine.
> 
> I started hacking on that, to get an idea of what it would look like
> and came up with the attached patch, to be applied on top of all your
> patches. It's still very messy, it needs quite a lot of cleanup before
> it can be committed, but I think the resulting switch-case state
> machine in XLogReadRecord() is quite straightforward at high level,
> with four states.

Sorry for late reply. It seems less messy than I thought it could
be if I refactored it more aggressively.

> I made some further changes to the XLogReadRecord() interface:
> 
> * If you pass a valid ReadPtr (i.e. the starting point to read from)
> * argument to XLogReadRecord(), it always restarts reading from that
> * record, even if it was in the middle of reading another record
> * previously. (Perhaps it would be more convenient to provide a separate
> * function to set the starting point, and remove the RecPtr argument
> * from XLogReadRecord altogther?)

Seems reasonable. randAccess property was replaced with the
state.PrevRecPtr = Invalid. It is easier to understand for me.

> * XLogReaderState->readBuf is now allocated and controlled by the
> * caller, not by xlogreader.c itself. When XLogReadRecord() needs data,
> * the caller makes the data available in readBuf, which can point to the
> * same buffer in all calls, or the caller may allocate a new buffer, or
> * it may point to a part of a larger buffer, whatever is convenient for
> * the caller. (Currently, all callers just allocate a BLCKSZ'd buffer,
> * though). The caller also sets readPagPtr, readLen and readPageTLI to
> * tell XLogReadRecord() what's in the buffer. So all these read* fields
> * are now set by the caller, XLogReadRecord() only reads them.

The caller knows how many byes to be read. So the caller provides
the required buffer seems reasonable.

> * In your patch, if XLogReadRecord() was called with state->readLen ==
> * -1, XLogReadRecord() returned an error. That seemed a bit silly; if an
> * error happened while reading the data, why call XLogReadRecord() at
> * all? You could just report the error directly. So I removed that.

Agreed. I forgot to move the error handling to more proper location.

> I'm not sure how intelligible this patch is in its current state. But
> I think the general idea is good. I plan to clean it up further next
> week, but feel free to work on it before that, either based on this
> patch or by starting afresh from your patch set.

I think you diff is intelligible enough for me. I'll take this if
you haven't done. Anyway I'm staring on this.

Thanks!

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2019-07-29 Thread Heikki Linnakangas

On 12/07/2019 10:10, Kyotaro Horiguchi wrote:

At Tue, 28 May 2019 04:45:24 -0700, Andres Freund  wrote in 
<20190528114524.dvj6ymap2virl...@alap3.anarazel.de>

Hi,

On 2019-04-18 21:02:57 +0900, Kyotaro HORIGUCHI wrote:

Hello. As mentioned before [1], read_page callback in
XLogReaderState is a cause of headaches. Adding another
remote-controlling stuff to xlog readers makes things messier [2].

I refactored XLOG reading functions so that we don't need the
callback. In short, ReadRecrod now calls XLogPageRead directly
with the attached patch set.

| while (XLogReadRecord(xlogreader, RecPtr, , )
|== XLREAD_NEED_DATA)
| XLogPageRead(xlogreader, fetching_ckpt, emode, randAccess);

On the other hand, XLogReadRecord became a bit complex. The patch
makes XLogReadRecord a state machine. I'm not confident that the
additional complexity is worth doing. Anyway I'll gegister this
to the next CF.


Just FYI, to me this doesn't clearly enough look like an improvement,
for a change of this size.


Thanks for the opiniton. I kinda agree about size but it is a
decision between "having multiple callbacks called under the
hood" vs "just calling a series of functions".  I think the
patched XlogReadRecord is easy to use in many situations.

It would be better if I could completely refactor the function
without the syntax tricks but I think the current patch is still
smaller and clearer than overhauling it.


I like the idea of refactoring XLogReadRecord() to not use a callback, 
and return a XLREAD_NEED_DATA value instead. It feels like a nicer, 
easier-to-use, interface, given that all the page-read functions need 
quite a bit of state and internal logic themselves. I remember that I 
felt that that would be a nicer interface when we originally extracted 
xlogreader.c into a reusable module, but I didn't want to make such big 
changes to XLogReadRecord() at that point.


I don't much like the "continuation" style of implementing the state 
machine. Nothing wrong with such a style in principle, but we don't do 
that anywhere else, and the macros seem like overkill, and turning the 
local variables static is pretty ugly. But I think XLogReadRecord() 
could be rewritten into a more traditional state machine.


I started hacking on that, to get an idea of what it would look like and 
came up with the attached patch, to be applied on top of all your 
patches. It's still very messy, it needs quite a lot of cleanup before 
it can be committed, but I think the resulting switch-case state machine 
in XLogReadRecord() is quite straightforward at high level, with four 
states.


I made some further changes to the XLogReadRecord() interface:

* If you pass a valid ReadPtr (i.e. the starting point to read from) 
argument to XLogReadRecord(), it always restarts reading from that 
record, even if it was in the middle of reading another record 
previously. (Perhaps it would be more convenient to provide a separate 
function to set the starting point, and remove the RecPtr argument from 
XLogReadRecord altogther?)


* XLogReaderState->readBuf is now allocated and controlled by the 
caller, not by xlogreader.c itself. When XLogReadRecord() needs data, 
the caller makes the data available in readBuf, which can point to the 
same buffer in all calls, or the caller may allocate a new buffer, or it 
may point to a part of a larger buffer, whatever is convenient for the 
caller. (Currently, all callers just allocate a BLCKSZ'd buffer, 
though). The caller also sets readPagPtr, readLen and readPageTLI to 
tell XLogReadRecord() what's in the buffer. So all these read* fields 
are now set by the caller, XLogReadRecord() only reads them.


* In your patch, if XLogReadRecord() was called with state->readLen == 
-1, XLogReadRecord() returned an error. That seemed a bit silly; if an 
error happened while reading the data, why call XLogReadRecord() at all? 
You could just report the error directly. So I removed that.


I'm not sure how intelligible this patch is in its current state. But I 
think the general idea is good. I plan to clean it up further next week, 
but feel free to work on it before that, either based on this patch or 
by starting afresh from your patch set.


- Heikki
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index e7a086b71e8..8f07450f503 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1385,6 +1385,7 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
 	XLogRecord *record;
 	XLogReaderState *xlogreader;
 	char	   *errormsg;
+	XLogRecPtr ptr;
 
 	xlogreader = XLogReaderAllocate(wal_segment_size);
 	if (!xlogreader)
@@ -1392,10 +1393,15 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
 (errcode(ERRCODE_OUT_OF_MEMORY),
  errmsg("out of memory"),
  errdetail("Failed while allocating a WAL reading processor.")));
+	xlogreader->readBuf = palloc(XLOG_BLCKSZ);
 
-	while 

Re: Remove page-read callback from XLogReaderState.

2019-07-12 Thread Kyotaro Horiguchi
At Tue, 28 May 2019 04:45:24 -0700, Andres Freund  wrote in 
<20190528114524.dvj6ymap2virl...@alap3.anarazel.de>
> Hi,
> 
> On 2019-04-18 21:02:57 +0900, Kyotaro HORIGUCHI wrote:
> > Hello. As mentioned before [1], read_page callback in
> > XLogReaderState is a cause of headaches. Adding another
> > remote-controlling stuff to xlog readers makes things messier [2].
> > 
> > I refactored XLOG reading functions so that we don't need the
> > callback. In short, ReadRecrod now calls XLogPageRead directly
> > with the attached patch set.
> > 
> > | while (XLogReadRecord(xlogreader, RecPtr, , )
> > |== XLREAD_NEED_DATA)
> > | XLogPageRead(xlogreader, fetching_ckpt, emode, randAccess);
> > 
> > On the other hand, XLogReadRecord became a bit complex. The patch
> > makes XLogReadRecord a state machine. I'm not confident that the
> > additional complexity is worth doing. Anyway I'll gegister this
> > to the next CF.
> 
> Just FYI, to me this doesn't clearly enough look like an improvement,
> for a change of this size.

Thanks for the opiniton. I kinda agree about size but it is a
decision between "having multiple callbacks called under the
hood" vs "just calling a series of functions".  I think the
patched XlogReadRecord is easy to use in many situations.

It would be better if I could completely refactor the function
without the syntax tricks but I think the current patch is still
smaller and clearer than overhauling it.

If many of the folks think that adding a callback is better than
this refactoring, I will withdraw this..

reagrds.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center




Re: Remove page-read callback from XLogReaderState.

2019-07-09 Thread Kyotaro Horiguchi
Hello. The patch gets disliked by my tool chain. Fixed the usage
of PG_USED_FOR_ASSERTS_ONLY and rebased to bd56cd75d2.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 1dabdce6993b73408b950cb8c348c4999178b9a0 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 18 Apr 2019 10:22:49 +0900
Subject: [PATCH 01/10] Define macros to make XLogReadRecord a state machine

To minimize apparent impact on code, use some macros as syntax
sugar. This is a similar stuff with ExecInterpExpr but a bit
different. The most significant difference is that this stuff allows
some functions are leaved midst of their work then continue. Roughly
speaking this is used as the follows.

enum retval
some_func()
{
  static .. internal_variables;

  XLR_SWITCH(INITIAL_STATUS);
  ...
  XLR_LEAVE(STATUS1, RETVAL_CONTINUE);
  ...
  XLR_LEAVE(STATUS2, RETVAL_CONTINUE2);
  ...
  XLR_SWITCH_END();

  XLR_RETURN(RETVAL_FINISH);
}

The caller uses the function as follows:

  while (some_func() != RETVAL_FINISH)
  {
;
  }
---
 src/backend/access/transam/xlogreader.c | 83 +
 1 file changed, 83 insertions(+)

diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 41dae916b4..69d20e1f2f 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -29,6 +29,89 @@
 #include "utils/memutils.h"
 #endif
 
+/*
+ * Use computed-goto-based state dispatch when computed gotos are available.
+ * But use a separate symbol so that it's easy to adjust locally in this file
+ * for development and testing.
+ */
+#ifdef HAVE_COMPUTED_GOTO
+#define XLR_USE_COMPUTED_GOTO
+#endif			/* HAVE_COMPUTED_GOTO */
+
+/*
+ * The state machine functions relies on static local variables. They cannot
+ * be reentered after non-local exit using ereport/elog for consistency. The
+ * assertion macros protect the functions from reenter after non-local exit.
+ */
+#ifdef USE_ASSERT_CHECKING
+#define XLR_REENT_PROTECT_ENTER() \
+	do { Assert(!__xlr_running); __xlr_running = true; } while (0)
+#define XLR_REENT_PROTECT_LEAVE()\
+	do { __xlr_running = false; } while (0)
+#else
+#define XLR_REENT_PROTECT_ENTER()
+#define XLR_REENT_PROTECT_LEAVE()
+#endif
+
+/*
+ * Macros for state dispatch.
+ *
+ * XLR_SWITCH - prologue code for state machine including switch itself.
+ * XLR_CASE - labels the implementation of named state.
+ * XLR_LEAVE - leave the function and return here at the next call.
+ * XLR_RETURN - return from the function and set state to initial state.
+ * XLR_END - just hides the closing brace if not in use.
+ */
+#if defined(XLR_USE_COMPUTED_GOTO)
+#define XLR_SWITCH(name)		\
+	static bool __xlr_running PG_USED_FOR_ASSERTS_ONLY = false; \
+	static void *__xlr_init_state = &\
+	static void *__xlr_state = &	\
+	do {\
+		XLR_REENT_PROTECT_ENTER();		\
+		goto *__xlr_state;\
+		XLR_CASE(name);	\
+	} while (0)
+#define XLR_CASE(name)		name:
+#define XLR_LEAVE(name, code)			\
+	do {\
+		__xlr_state = (&);			\
+		XLR_REENT_PROTECT_LEAVE();		\
+		return (code);	\
+		XLR_CASE(name);	\
+	} while (0)
+#define XLR_RETURN(code)		\
+	do {		\
+		__xlr_state = __xlr_init_state;			\
+		XLR_REENT_PROTECT_LEAVE();\
+		return (code);			\
+	} while (0)
+#define XLR_SWITCH_END()
+#else			/* !XLR_USE_COMPUTED_GOTO */
+#define XLR_SWITCH(name)\
+	static bool __xlr_running = false PG_USED_FOR_ASSERTS_ONLY;			\
+	static int __xlr_init_state = name;	\
+	static int __xlr_state = name;		\
+	XLR_REENT_PROTECT_ENTER();			\
+	switch (__xlr_state) {\
+	XLR_CASE(name)
+#define XLR_CASE(name)		case name:
+#define XLR_LEAVE(name, code)			\
+	do {\
+		__xlr_state = (name);			\
+		XLR_REENT_PROTECT_LEAVE();		\
+		return (code);	\
+		XLR_CASE(name);	\
+	} while (0)
+#define XLR_RETURN(code)		\
+	do {		\
+		__xlr_state = __xlr_init_state;	\
+		XLR_REENT_PROTECT_LEAVE();		\
+		return (code);	\
+	} while (0)
+#define XLR_SWITCH_END()	}
+#endif			/* XLR_USE_COMPUTED_GOTO */
+
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
 
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
-- 
2.16.3

>From 6c36b3c428ac1160b4211710331c1cfee5f83ab9 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Wed, 17 Apr 2019 14:15:16 +0900
Subject: [PATCH 02/10] Make ReadPageInternal a state machine

This patch set aims to remove read_page call back from
XLogReaderState. This is done in two steps. This patch does the first
step. Makes ReadPageInternal, which currently calling read_page
callback, a state machine and move the caller sites to XLogReadRecord
and other direct callers of the callback.
---
 

Re: Remove page-read callback from XLogReaderState.

2019-05-28 Thread Andres Freund
Hi,

On 2019-04-18 21:02:57 +0900, Kyotaro HORIGUCHI wrote:
> Hello. As mentioned before [1], read_page callback in
> XLogReaderState is a cause of headaches. Adding another
> remote-controlling stuff to xlog readers makes things messier [2].
> 
> I refactored XLOG reading functions so that we don't need the
> callback. In short, ReadRecrod now calls XLogPageRead directly
> with the attached patch set.
> 
> | while (XLogReadRecord(xlogreader, RecPtr, , )
> |== XLREAD_NEED_DATA)
> | XLogPageRead(xlogreader, fetching_ckpt, emode, randAccess);
> 
> On the other hand, XLogReadRecord became a bit complex. The patch
> makes XLogReadRecord a state machine. I'm not confident that the
> additional complexity is worth doing. Anyway I'll gegister this
> to the next CF.

Just FYI, to me this doesn't clearly enough look like an improvement,
for a change of this size.

Greetings,

Andres Freund




Re: Remove page-read callback from XLogReaderState.

2019-05-28 Thread Antonin Houska
Kyotaro HORIGUCHI  wrote:

> v3-0001 : Changed macrosas suggested.

This attachment is missing, please send it too.

-- 
Antonin Houska
Web: https://www.cybertec-postgresql.com




Re: Remove page-read callback from XLogReaderState.

2019-05-23 Thread Kyotaro HORIGUCHI
Thank you for looking this, Antonin.

At Wed, 22 May 2019 13:53:23 +0200, Antonin Houska  wrote in 
<25494.1558526...@spoje.net>
> Kyotaro HORIGUCHI  wrote:
> 
> > Hello. Thank you for looking this.
> > ...
> > Yeah, I'll register this, maybe the week after next week.
> 
> I've checked the new version. One more thing I noticed now is that XLR_STATE.j
> is initialized to zero, either by XLogReaderAllocate() which zeroes the whole
> reader state, or later by XLREAD_RESET. This special value then needs to be
> handled here:
> 
> #define XLR_SWITCH()  \
>   do {\
>   if ((XLR_STATE).j)  \
>   goto *((void *) (XLR_STATE).j); \
>   XLR_CASE(XLR_INIT_STATE);   \
>   } while (0)
> 
> I think it's better to set the label always to (&_INIT_STATE) so that
> XLR_SWITCH can perform the jump unconditionally.

I thought the same but did not do that since label is
function-scoped so it cannot be referred outside the defined
function.

I moved the state variable from XLogReaderState into functions
static variable. It's not problem since the functions are
non-reentrant in the first place.

> Attached is also an (unrelated) comment fix proposal.

Sounds reasoable. I found another typo "acutually" there.

-int32readLen;/* bytes acutually read, must be larger than
+int32readLen;/* bytes acutually read, must be at least

I fixed it with other typos found.

v3-0001 : Changed macrosas suggested.

v3-0002, 0004: Fixed comments. Fixes following changes of
 macros. Renamed state symbols.

v3-0003, 0005-0010: No substantial change from v2.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 036b1a50ad79ebfde990e178bead9ba03c753d02 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Wed, 17 Apr 2019 14:15:16 +0900
Subject: [PATCH 02/10] Make ReadPageInternal a state machine

This patch set aims to remove read_page call back from
XLogReaderState. This is done in two steps. This patch does the first
step. Makes ReadPageInternal, which currently calling read_page
callback, a state machine and move the caller sites to XLogReadRecord
and other direct callers of the callback.
---
 src/backend/access/transam/xlog.c  |  15 ++-
 src/backend/access/transam/xlogreader.c| 180 +++--
 src/backend/access/transam/xlogutils.c |   8 +-
 src/backend/replication/logical/logicalfuncs.c |   6 +-
 src/backend/replication/walsender.c|  10 +-
 src/bin/pg_rewind/parsexlog.c  |  17 ++-
 src/bin/pg_waldump/pg_waldump.c|   8 +-
 src/include/access/xlogreader.h|  39 --
 src/include/access/xlogutils.h |   2 +-
 src/include/replication/logicalfuncs.h |   2 +-
 10 files changed, 177 insertions(+), 110 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 1c7dd51b9f..d1a29fe5cd 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -885,7 +885,7 @@ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 static int	XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 		 int source, bool notfoundOk);
 static int	XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
-static int	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+static void	XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		 int reqLen, XLogRecPtr targetRecPtr, char *readBuf,
 		 TimeLineID *readTLI);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
@@ -11507,7 +11507,7 @@ CancelBackup(void)
  * XLogPageRead() to try fetching the record from another source, or to
  * sleep and retry.
  */
-static int
+static void
 XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 			 XLogRecPtr targetRecPtr, char *readBuf, TimeLineID *readTLI)
 {
@@ -11566,7 +11566,8 @@ retry:
 			readLen = 0;
 			readSource = 0;
 
-			return -1;
+			xlogreader->readLen = -1;
+			return;
 		}
 	}
 
@@ -11661,7 +11662,8 @@ retry:
 		goto next_record_is_invalid;
 	}
 
-	return readLen;
+	xlogreader->readLen = readLen;
+	return;
 
 next_record_is_invalid:
 	lastSourceFailed = true;
@@ -11675,8 +11677,9 @@ next_record_is_invalid:
 	/* In standby-mode, keep trying */
 	if (StandbyMode)
 		goto retry;
-	else
-		return -1;
+
+	xlogreader->readLen = -1;
+	return;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index baf04b9f1f..f7499aff5e 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -118,8 +118,8 @@ static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
   XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess);
 static bool 

Re: Remove page-read callback from XLogReaderState.

2019-05-22 Thread Antonin Houska
Kyotaro HORIGUCHI  wrote:

> Hello. Thank you for looking this.
> ...
> Yeah, I'll register this, maybe the week after next week.

I've checked the new version. One more thing I noticed now is that XLR_STATE.j
is initialized to zero, either by XLogReaderAllocate() which zeroes the whole
reader state, or later by XLREAD_RESET. This special value then needs to be
handled here:

#define XLR_SWITCH()\
do {\
if ((XLR_STATE).j)  \
goto *((void *) (XLR_STATE).j); \
XLR_CASE(XLR_INIT_STATE);   \
} while (0)

I think it's better to set the label always to (&_INIT_STATE) so that
XLR_SWITCH can perform the jump unconditionally.

Attached is also an (unrelated) comment fix proposal.

-- 
Antonin Houska
Web: https://www.cybertec-postgresql.com

diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index 262bf0e77f..cb864a86d8 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -124,7 +124,7 @@ struct XLogReaderState
 	XLogRecPtr	currRecPtr;		/* beginning of the WAL record being read */
 
 	/* return from page reader */
-	int32		readLen;		/* bytes acutually read, must be larger than
+	int32		readLen;		/* bytes acutually read, must be at least
  * loadLen. -1 on error. */
 	TimeLineID	readPageTLI;	/* TLI for data currently in readBuf */
 


Re: Remove page-read callback from XLogReaderState.

2019-04-26 Thread Kyotaro HORIGUCHI
Hello. Thank you for looking this.

At Thu, 25 Apr 2019 13:58:20 +0200, Antonin Houska  wrote in 
<18581.1556193500@localhost>
> Kyotaro HORIGUCHI  wrote:
> 
> > Hello. As mentioned before [1], read_page callback in
> > XLogReaderState is a cause of headaches. Adding another
> > remote-controlling stuff to xlog readers makes things messier [2].
> 
> The patch I posted in thread [2] tries to solve another problem: it tries to
> merge xlogutils.c:XLogRead(), walsender.c:XLogRead() and
> pg_waldump.c:XLogDumpXLogRead() into a single function,
> xlogutils.c:XLogRead().
> 
> > [2]
> > https://www.postgresql.org/message-id/20190412.122711.158276916.horiguchi.kyot...@lab.ntt.co.jp
> 
> > I refactored XLOG reading functions so that we don't need the
> > callback.
> 
> I was curious about the patch, so I reviewed it:

Thnak for the comment. (It's a shame that I might made it more complex..)

> * xlogreader.c
> 
>   ** Comments mention "opcode", "op" and "expression step" - probably leftover
>  from the executor, which seems to have inspired you.

Uggh. Yes, exactly. I believed change them all. Fixed.

>   ** XLR_DISPATCH() seems to be unused

Right. XLR_ macros are used to dispatch internally in a function
differently from EEO_ macros so I thought it uesless but I
hesitated to remove it. I remove it.

>   ** Comment: "duplicatedly" -> "repeatedly" ?

It aimed reentrance. But I notieced that it doesn't work when
ERROR-exiting. So I remove the assertion and related code..

>   ** XLogReadRecord(): comment "All internal state need ..." -> "needs"

Fixed.

>   ** XLogNeedData()
> 
>  *** shouldn't only the minimum amount of data needed (SizeOfXLogLongPHD)
>  be requested here?
> 
>   state->loadLen = XLOG_BLCKSZ;
>   XLR_LEAVE(XLND_STATE_SEGHEAD, true);
> 
> Note that ->loadLen is also set only to the minimum amount of data needed
> elsewhere.

Maybe right, but it is existing behavior so I preserved it as
focusing on refactoring.

>  *** you still mention "read_page callback" in a comment.

Thanks. "the read_page callback" were translated to "the caller"
and it seems the last one.

>  *** state->readLen is checked before one of the calls of XLR_LEAVE(), but
>  I think it should happen before *each* call. Otherwise data can be read
>  from the page even if it's already in the buffer.

That doesn't happen since XLogReadRecord doesn't LEAVE unless
XLogNeedData returns true (that is, needs more data) and
XLogNeedData returns true only when requested data is not on the
buffer yet. (If I refactored it correctly and it seems to me so.)

> * xlogreader.h
> 
>   ** XLND_STATE_PAGEFULLHEAD - maybe LONG rather than FULL? And perhaps HEAD
>   -> HDR, so it's clear that it's about (page) header, not e.g. list head.

Perhaps that's better. Thanks.

> 
>   ** XLogReaderState.loadLen - why not reqLen? loadLen sounds to me like 
> "loaded"
>   as opposed to "requested". And assignemnt like this
>
>   int reqLen  = xlogreader->loadLen;
> 
>   will also be less confusing with ->reqLen.
> 
>   Maybe also ->loadPagePtr should be renamed to ->targetPagePtr.

Yeah, that's annoyance. reqLen *was* actually the "requested"
length to XLogNeedData FKA ReadPageInternal, but in the current
shape XLogNeedData makes different request to the callers (when
fetching the first page in the newly visited segment), so the two
(req(uest)Len and (to be)loadLen) are different things. At the
same time, targetPagePoint is different from loadPagePtr.

Of course the naming as arguable.

> * trailing whitespace: xlogreader.h:130, xlogreader.c:1058

Thanks, it have been fixed on my repo.

> * The 2nd argument of SimpleXLogPageRead() is "private", which seems too
>   generic given that the function is no longer used as a callback. Since the
>   XLogPageReadPrivate structure only has two fields, I think it'd be o.k. to
>   pass them to the function directly.

Sound reasonable. Fixed.

> * I haven't found CF entry for this patch.

Yeah, I'll register this, maybe the week after next week.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From cff0f38cc03c2186505cad30b27115bc0228b42f Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 18 Apr 2019 10:22:49 +0900
Subject: [PATCH 01/10] Define macros to make XLogReadRecord a state machine

To minimize apparent imapct on code, use some macros as syntax sugar. This is a similar stuff with ExecInterpExpr but a bit different. The most significant difference is that  this stuff allows some functions are leaved midst of their work then continue. Roughly speaking this is used as the follows.

enum retval
some_func()
{
  static .. internal_variables;

  XLR_SWITCH();
  ...
  XLR_LEAVE(STATUS1, RETVAL_CONTINUE);
  ...
  XLR_LEAVE(STATUS2, RETVAL_CONTINUE2);
  ...
  XLR_SWITCH_END();

  XLR_RETURN(RETVAL_FINISH);
}

The caller uses the function as follows:

  while (some_func() != RETVAL_FINISH)
  {
;
  }
---
 src/backend/access/transam/xlogreader.c | 53 

Re: Remove page-read callback from XLogReaderState.

2019-04-25 Thread Antonin Houska
Kyotaro HORIGUCHI  wrote:

> Hello. As mentioned before [1], read_page callback in
> XLogReaderState is a cause of headaches. Adding another
> remote-controlling stuff to xlog readers makes things messier [2].

The patch I posted in thread [2] tries to solve another problem: it tries to
merge xlogutils.c:XLogRead(), walsender.c:XLogRead() and
pg_waldump.c:XLogDumpXLogRead() into a single function,
xlogutils.c:XLogRead().

> [2]
> https://www.postgresql.org/message-id/20190412.122711.158276916.horiguchi.kyot...@lab.ntt.co.jp

> I refactored XLOG reading functions so that we don't need the
> callback.

I was curious about the patch, so I reviewed it:

* xlogreader.c

  ** Comments mention "opcode", "op" and "expression step" - probably leftover
 from the executor, which seems to have inspired you.

  ** XLR_DISPATCH() seems to be unused

  ** Comment: "duplicatedly" -> "repeatedly" ?

  ** XLogReadRecord(): comment "All internal state need ..." -> "needs"

  ** XLogNeedData()

 *** shouldn't only the minimum amount of data needed (SizeOfXLogLongPHD)
 be requested here?

state->loadLen = XLOG_BLCKSZ;
XLR_LEAVE(XLND_STATE_SEGHEAD, true);

Note that ->loadLen is also set only to the minimum amount of data needed
elsewhere.

 *** you still mention "read_page callback" in a comment.

 *** state->readLen is checked before one of the calls of XLR_LEAVE(), but
 I think it should happen before *each* call. Otherwise data can be read
 from the page even if it's already in the buffer.

* xlogreader.h

  ** XLND_STATE_PAGEFULLHEAD - maybe LONG rather than FULL? And perhaps HEAD
  -> HDR, so it's clear that it's about (page) header, not e.g. list head.

  ** XLogReaderState.loadLen - why not reqLen? loadLen sounds to me like 
"loaded"
  as opposed to "requested". And assignemnt like this

int reqLen  = xlogreader->loadLen;

  will also be less confusing with ->reqLen.

  Maybe also ->loadPagePtr should be renamed to ->targetPagePtr.


* trailing whitespace: xlogreader.h:130, xlogreader.c:1058


* The 2nd argument of SimpleXLogPageRead() is "private", which seems too
  generic given that the function is no longer used as a callback. Since the
  XLogPageReadPrivate structure only has two fields, I think it'd be o.k. to
  pass them to the function directly.

* I haven't found CF entry for this patch.

-- 
Antonin Houska
Web: https://www.cybertec-postgresql.com




Remove page-read callback from XLogReaderState.

2019-04-18 Thread Kyotaro HORIGUCHI
Hello. As mentioned before [1], read_page callback in
XLogReaderState is a cause of headaches. Adding another
remote-controlling stuff to xlog readers makes things messier [2].

I refactored XLOG reading functions so that we don't need the
callback. In short, ReadRecrod now calls XLogPageRead directly
with the attached patch set.

| while (XLogReadRecord(xlogreader, RecPtr, , )
|== XLREAD_NEED_DATA)
| XLogPageRead(xlogreader, fetching_ckpt, emode, randAccess);

On the other hand, XLogReadRecord became a bit complex. The patch
makes XLogReadRecord a state machine. I'm not confident that the
additional complexity is worth doing. Anyway I'll gegister this
to the next CF.

[1] 
https://www.postgresql.org/message-id/47215279-228d-f30d-35d1-16af695e5...@iki.fi

[2] 
https://www.postgresql.org/message-id/20190412.122711.158276916.horiguchi.kyot...@lab.ntt.co.jp

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 3de14fb47987e9dd8189bfad3ca7264c26b719eb Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi 
Date: Thu, 18 Apr 2019 10:22:49 +0900
Subject: [PATCH 01/10] Define macros to make XLogReadRecord a state machine

To minimize apparent imapct on code, use some macros as syntax sugar. This is a similar stuff with ExecInterpExpr but a bit different. The most significant difference is that  this stuff allows some functions are leaved midst of their work then continue. Roughly speaking this is used as the follows.

enum retval
some_func()
{
  static .. internal_variables;

  XLR_SWITCH();
  ...
  XLR_LEAVE(STATUS1, RETVAL_CONTINUE);
  ...
  XLR_LEAVE(STATUS2, RETVAL_CONTINUE2);
  ...
  XLR_SWITCH_END();

  XLR_RETURN(RETVAL_FINISH);
}

The caller uses the function as follows:

  while (some_func() != RETVAL_FINISH)
  {
;
  }
---
 src/backend/access/transam/xlogreader.c | 63 +
 src/include/access/xlogreader.h |  3 ++
 2 files changed, 66 insertions(+)

diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 9196aa3aae..5299765040 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -29,6 +29,69 @@
 #include "utils/memutils.h"
 #endif
 
+/*
+ * Use computed-goto-based opcode dispatch when computed gotos are available.
+ * But use a separate symbol so that it's easy to adjust locally in this file
+ * for development and testing.
+ */
+#ifdef HAVE_COMPUTED_GOTO
+#define XLR_USE_COMPUTED_GOTO
+#endif			/* HAVE_COMPUTED_GOTO */
+
+/*
+ * Macros for opcode dispatch.
+ *
+ * XLR_SWITCH - just hides the switch if not in use.
+ * XLR_CASE - labels the implementation of named expression step type.
+ * XLR_DISPATCH - jump to the implementation of the step type for 'op'.
+ * XLR_LEAVE - leave the function and return here at the next call.
+ * XLR_RETURN - return from the function and set state to initial state.
+ * XLR_END - just hides the closing brace if not in use.
+ */
+#if defined(XLR_USE_COMPUTED_GOTO)
+#define XLR_SWITCH()		\
+	/* Don't call duplicatedly */			\
+	static int callcnt = 0 PG_USED_FOR_ASSERTS_ONLY;		\
+	do {	\
+		if ((XLR_STATE).j)	\
+			goto *((void *) (XLR_STATE).j);	\
+		XLR_CASE(XLR_INIT_STATE);			\
+		Assert(++callcnt == 1);\
+	} while (0)
+#define XLR_CASE(name)		name:
+#define XLR_DISPATCH()		goto *((void *) (XLR_STATE).j)
+#define XLR_LEAVE(name, code) do {\
+		(XLR_STATE).j = (&); return (code);	\
+		XLR_CASE(name);\
+	} while (0)
+#define XLR_RETURN(code) \
+  do {		\
+	  Assert(--callcnt == 0);\
+	  (XLR_STATE).j = (&_INIT_STATE); return (code);	\
+  } while (0)
+#define XLR_SWITCH_END()
+#else			/* !XLR_USE_COMPUTED_GOTO */
+#define XLR_SWITCH() \
+	/* Don't call duplicatedly */	 \
+	static int callcnt = 0 PG_USED_FOR_ASSERTS_ONLY; \
+	switch ((XLR_STATE).c) {		 \
+	XLR_CASE(XLR_INIT_STATE);		 \
+	Assert(++callcnt == 1);			 \
+#define XLR_CASE(name)		case name:
+#define XLR_DISPATCH()		goto starteval
+#define XLR_LEAVE(name, code) \
+  do {			\
+	  (XLR_STATE).c = (name); return (code);	\
+	  XLR_CASE(name);			\
+  } while (0)
+#define XLR_RETURN(code) \
+  do {		\
+	  Assert(--callcnt == 0);\
+	  (XLR_STATE).c = (XLR_INIT_STATE); return (code);		\
+  } while (0)
+#define XLR_SWITCH_END()	}
+#endif			/* XLR_USE_COMPUTED_GOTO */
+
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
 
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index f3bae0bf49..30500c35c7 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -240,6 +240,9 @@ extern bool DecodeXLogRecord(XLogReaderState *state, XLogRecord *record,
 #define XLogRecBlockImageApply(decoder, block_id) \
 	((decoder)->blocks[block_id].apply_image)
 
+/* Reset the