[PATCH] XLogReadRecord returns pointer to currently read page

Started by Andrey Lepikhovover 7 years ago18 messages
#1Andrey Lepikhov
a.lepikhov@postgrespro.ru
1 attachment(s)

Hi, hackers!

I propose the patch for fix one small code defect.
The XLogReadRecord() function reads the pages of a WAL segment that
contain a WAL-record. Then it creates a readRecordBuf buffer in private
memory of a backend and copy record from the pages to the readRecordBuf
buffer. Pointer 'record' is set to the beginning of the readRecordBuf
buffer.

But if the WAL-record is fully placed on one page, the XLogReadRecord()
function forgets to bind the "record" pointer with the beginning of the
readRecordBuf buffer. In this case, XLogReadRecord() returns a pointer
to an internal xlog page. This patch fixes the defect.

Previously, in all cases of using WAL this was not a problem. However if
you plan to perform some decoding operations before returning the WAL
record to the caller (this is my case), this can lead to bugs that are
difficult to catch.

--
Andrey Lepikhov
Postgres Professional
https://postgrespro.com
The Russian Postgres Company

Attachments:

0001-WAL-record-local-buffer-pointer-fix.patchtext/x-patch; name=0001-WAL-record-local-buffer-pointer-fix.patchDownload
From 0a7d7bf07eb91a959b2864a7497088c4d203aaa4 Mon Sep 17 00:00:00 2001
From: "Andrey V. Lepikhov" <a.lepikhov@postgrespro.ru>
Date: Fri, 17 Aug 2018 07:56:30 +0500
Subject: [PATCH] WAL record local buffer pointer fix

---
 src/backend/access/transam/xlogreader.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 4c633c6c49..7bccc68189 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -480,6 +480,7 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 
 		state->ReadRecPtr = RecPtr;
 		memcpy(state->readRecordBuf, record, total_len);
+		record = (XLogRecord *) state->readRecordBuf;
 	}
 
 	/*
-- 
2.17.1

#2Michael Paquier
michael@paquier.xyz
In reply to: Andrey Lepikhov (#1)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On Fri, Aug 17, 2018 at 08:47:15AM +0500, Andrey Lepikhov wrote:

Previously, in all cases of using WAL this was not a problem. However if you
plan to perform some decoding operations before returning the WAL record to
the caller (this is my case), this can lead to bugs that are difficult to
catch.

What kind of cases with logical decoding are you referring to? If
any of them can be reproduced with upstream, could you send a
reproducer, or a way to see it?
--
Michael

#3Andrey Lepikhov
a.lepikhov@postgrespro.ru
In reply to: Michael Paquier (#2)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

17.08.2018 08:55, Michael Paquier пишет:

On Fri, Aug 17, 2018 at 08:47:15AM +0500, Andrey Lepikhov wrote:

Previously, in all cases of using WAL this was not a problem. However if you
plan to perform some decoding operations before returning the WAL record to
the caller (this is my case), this can lead to bugs that are difficult to
catch.

What kind of cases with logical decoding are you referring to? If
any of them can be reproduced with upstream, could you send a
reproducer, or a way to see it?
--
Michael

I'm working on the problem of a WAL-record size reducing. One of the
PostgreSQL experimental extensions uses a 64-bit xid, and the XLogRecord
size is increased to 32 bytes.
Representing a 64-bit xid in WAL Segment as a pair (16-bit base, 8-bit
offset) reduces the size of the WAL record header and its body.
So, I encode a WAL-record in XLogInsertRecord() (decreasing the size)
just before writing to a shared memory pages and performs the decoding
just before processing DecodeXLogRecord() operation.
It looks like a layer in the xlog subsystem for additional WAL
compression. However, this is a long story ...

--
Andrey Lepikhov
Postgres Professional
https://postgrespro.com
The Russian Postgres Company

#4Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Andrey Lepikhov (#1)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On 17/08/2018 06:47, Andrey Lepikhov wrote:

I propose the patch for fix one small code defect.
The XLogReadRecord() function reads the pages of a WAL segment that
contain a WAL-record. Then it creates a readRecordBuf buffer in private
memory of a backend and copy record from the pages to the readRecordBuf
buffer. Pointer 'record' is set to the beginning of the readRecordBuf
buffer.

But if the WAL-record is fully placed on one page, the XLogReadRecord()
function forgets to bind the "record" pointer with the beginning of the
readRecordBuf buffer. In this case, XLogReadRecord() returns a pointer
to an internal xlog page. This patch fixes the defect.

Hmm. I agree it looks weird the way it is. But I wonder, why do we even
copy the record to readRecordBuf, if it fits on the WAL page? Returning
a pointer to the xlog page buffer seems OK in that case. What if we
remove the memcpy(), instead?

- Heikki

#5Andrey Lepikhov
a.lepikhov@postgrespro.ru
In reply to: Heikki Linnakangas (#4)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On 22.10.2018 2:06, Heikki Linnakangas wrote:

On 17/08/2018 06:47, Andrey Lepikhov wrote:

I propose the patch for fix one small code defect.
The XLogReadRecord() function reads the pages of a WAL segment that
contain a WAL-record. Then it creates a readRecordBuf buffer in private
memory of a backend and copy record from the pages to the readRecordBuf
buffer. Pointer 'record' is set to the beginning of the readRecordBuf
buffer.

But if the WAL-record is fully placed on one page, the XLogReadRecord()
function forgets to bind the "record" pointer with the beginning of the
readRecordBuf buffer. In this case, XLogReadRecord() returns a pointer
to an internal xlog page. This patch fixes the defect.

Hmm. I agree it looks weird the way it is. But I wonder, why do we even
copy the record to readRecordBuf, if it fits on the WAL page? Returning
a pointer to the xlog page buffer seems OK in that case. What if we
remove the memcpy(), instead?

It depends on the PostgreSQL roadmap. If we want to compress main data
and encode something to reduce a WAL-record size, than the
representation of the WAL-record in shared buffers (packed) and in local
memory (unpacked) will be different and the patch is needed.
If something like this should not be in the PostgreSQL core, then it is
more efficient to remove memcpy(), of course.
I vote for the patch.

--
Andrey Lepikhov
Postgres Professional
https://postgrespro.com
The Russian Postgres Company

#6Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Andrey Lepikhov (#5)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On 22/10/2018 20:54, Andrey Lepikhov wrote:

On 22.10.2018 2:06, Heikki Linnakangas wrote:

On 17/08/2018 06:47, Andrey Lepikhov wrote:

I propose the patch for fix one small code defect.
The XLogReadRecord() function reads the pages of a WAL segment that
contain a WAL-record. Then it creates a readRecordBuf buffer in private
memory of a backend and copy record from the pages to the readRecordBuf
buffer. Pointer 'record' is set to the beginning of the readRecordBuf
buffer.

But if the WAL-record is fully placed on one page, the XLogReadRecord()
function forgets to bind the "record" pointer with the beginning of the
readRecordBuf buffer. In this case, XLogReadRecord() returns a pointer
to an internal xlog page. This patch fixes the defect.

Hmm. I agree it looks weird the way it is. But I wonder, why do we even
copy the record to readRecordBuf, if it fits on the WAL page? Returning
a pointer to the xlog page buffer seems OK in that case. What if we
remove the memcpy(), instead?

It depends on the PostgreSQL roadmap. If we want to compress main data
and encode something to reduce a WAL-record size, than the
representation of the WAL-record in shared buffers (packed) and in local
memory (unpacked) will be different and the patch is needed.

I'd expect the decompression to read from the on-disk buffer, and unpack
to readRecordBuf, I still don't see a need to copy the packed record to
readRecordBuf. If there is a need for that, though, the patch that
implements the packing or compression can add the memcpy() where it
needs it.

- Heikki

#7Andrey Lepikhov
a.lepikhov@postgrespro.ru
In reply to: Heikki Linnakangas (#6)
1 attachment(s)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On 23.10.2018 0:53, Heikki Linnakangas wrote:

I'd expect the decompression to read from the on-disk buffer, and unpack
to readRecordBuf, I still don't see a need to copy the packed record to
readRecordBuf. If there is a need for that, though, the patch that
implements the packing or compression can add the memcpy() where it
needs it.

I agree with it. Eventually, placement of the WAL-record can be defined
by comparison the record, readBuf and readRecordBuf pointers.
In attachment new version of the patch.

--
Andrey Lepikhov
Postgres Professional
https://postgrespro.com
The Russian Postgres Company

Attachments:

0001-WAL-record-buffer-pointer-fix.patchtext/x-patch; name=0001-WAL-record-buffer-pointer-fix.patchDownload
From 36fd35dc75658f471efbc64fe2a3f204f0aa27e4 Mon Sep 17 00:00:00 2001
From: "Andrey V. Lepikhov" <a.lepikhov@postgrespro.ru>
Date: Tue, 23 Oct 2018 10:17:55 +0500
Subject: [PATCH] WAL-record-buffer-pointer-fix

---
 src/backend/access/transam/xlogreader.c | 27 ++++++++++++-------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 0768ca7822..c5e019bf77 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -353,19 +353,6 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 		gotheader = false;
 	}
 
-	/*
-	 * Enlarge readRecordBuf as needed.
-	 */
-	if (total_len > state->readRecordBufSize &&
-		!allocate_recordbuf(state, total_len))
-	{
-		/* We treat this as a "bogus data" condition */
-		report_invalid_record(state, "record length %u at %X/%X too long",
-							  total_len,
-							  (uint32) (RecPtr >> 32), (uint32) RecPtr);
-		goto err;
-	}
-
 	len = XLOG_BLCKSZ - RecPtr % XLOG_BLCKSZ;
 	if (total_len > len)
 	{
@@ -375,6 +362,19 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 		char	   *buffer;
 		uint32		gotlen;
 
+		/*
+		 * Enlarge readRecordBuf as needed.
+		 */
+		if (total_len > state->readRecordBufSize &&
+			!allocate_recordbuf(state, total_len))
+		{
+			/* We treat this as a "bogus data" condition */
+			report_invalid_record(state, "record length %u at %X/%X too long",
+								  total_len,
+								  (uint32) (RecPtr >> 32), (uint32) RecPtr);
+			goto err;
+		}
+
 		/* Copy the first fragment of the record from the first page. */
 		memcpy(state->readRecordBuf,
 			   state->readBuf + RecPtr % XLOG_BLCKSZ, len);
@@ -479,7 +479,6 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 		state->EndRecPtr = RecPtr + MAXALIGN(total_len);
 
 		state->ReadRecPtr = RecPtr;
-		memcpy(state->readRecordBuf, record, total_len);
 	}
 
 	/*
-- 
2.17.1

#8Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Andrey Lepikhov (#7)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

Hello.

At Tue, 23 Oct 2018 10:25:27 +0500, Andrey Lepikhov <a.lepikhov@postgrespro.ru> wrote in <2553f2b0-0e39-eb0e-d382-6c0ed08ca8ae@postgrespro.ru>

On 23.10.2018 0:53, Heikki Linnakangas wrote:

I'd expect the decompression to read from the on-disk buffer, and
unpack to readRecordBuf, I still don't see a need to copy the packed
record to readRecordBuf. If there is a need for that, though, the
patch that implements the packing or compression can add the memcpy()
where it needs it.

I agree with it. Eventually, placement of the WAL-record can be
defined by comparison the record, readBuf and readRecordBuf pointers.
In attachment new version of the patch.

This looks quite clear and what it does is reasonable to me.
Applies cleanly on top of current master and no regression seen.

Just one comment. This patch leaves the following code.

/* Record does not cross a page boundary */
if (!ValidXLogRecord(state, record, RecPtr))
goto err;

state->EndRecPtr = RecPtr + MAXALIGN(total_len);

!>

state->ReadRecPtr = RecPtr;
}

The empty line (marked by '!') looks a bit too much standing out
after this patch. Could you remove the line? Then could you
transpose the two assignments if you don't mind?

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#9Andrey Lepikhov
a.lepikhov@postgrespro.ru
In reply to: Kyotaro HORIGUCHI (#8)
1 attachment(s)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On 26.10.2018 10:33, Kyotaro HORIGUCHI wrote:

Hello.

At Tue, 23 Oct 2018 10:25:27 +0500, Andrey Lepikhov <a.lepikhov@postgrespro.ru> wrote in <2553f2b0-0e39-eb0e-d382-6c0ed08ca8ae@postgrespro.ru>

On 23.10.2018 0:53, Heikki Linnakangas wrote:

I'd expect the decompression to read from the on-disk buffer, and
unpack to readRecordBuf, I still don't see a need to copy the packed
record to readRecordBuf. If there is a need for that, though, the
patch that implements the packing or compression can add the memcpy()
where it needs it.

I agree with it. Eventually, placement of the WAL-record can be
defined by comparison the record, readBuf and readRecordBuf pointers.
In attachment new version of the patch.

This looks quite clear and what it does is reasonable to me.
Applies cleanly on top of current master and no regression seen.

Just one comment. This patch leaves the following code.

/* Record does not cross a page boundary */
if (!ValidXLogRecord(state, record, RecPtr))
goto err;

state->EndRecPtr = RecPtr + MAXALIGN(total_len);

!>

state->ReadRecPtr = RecPtr;
}

The empty line (marked by '!') looks a bit too much standing out
after this patch. Could you remove the line? Then could you
transpose the two assignments if you don't mind?

Thanks, see attachment.

--
Andrey Lepikhov
Postgres Professional
https://postgrespro.com
The Russian Postgres Company

Attachments:

0001-WAL-record-buffer-pointer-fix.patchtext/x-patch; name=0001-WAL-record-buffer-pointer-fix.patchDownload
From ec1df6c2b41fdfe2c79e3f0944653057e394c535 Mon Sep 17 00:00:00 2001
From: "Andrey V. Lepikhov" <a.lepikhov@postgrespro.ru>
Date: Tue, 23 Oct 2018 10:17:55 +0500
Subject: [PATCH] WAL record buffer pointer fix

---
 src/backend/access/transam/xlogreader.c | 30 ++++++++++++-------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 0768ca7822..82a16e78f3 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -353,19 +353,6 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 		gotheader = false;
 	}
 
-	/*
-	 * Enlarge readRecordBuf as needed.
-	 */
-	if (total_len > state->readRecordBufSize &&
-		!allocate_recordbuf(state, total_len))
-	{
-		/* We treat this as a "bogus data" condition */
-		report_invalid_record(state, "record length %u at %X/%X too long",
-							  total_len,
-							  (uint32) (RecPtr >> 32), (uint32) RecPtr);
-		goto err;
-	}
-
 	len = XLOG_BLCKSZ - RecPtr % XLOG_BLCKSZ;
 	if (total_len > len)
 	{
@@ -375,6 +362,19 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 		char	   *buffer;
 		uint32		gotlen;
 
+		/*
+		 * Enlarge readRecordBuf as needed.
+		 */
+		if (total_len > state->readRecordBufSize &&
+			!allocate_recordbuf(state, total_len))
+		{
+			/* We treat this as a "bogus data" condition */
+			report_invalid_record(state, "record length %u at %X/%X too long",
+								  total_len,
+								  (uint32) (RecPtr >> 32), (uint32) RecPtr);
+			goto err;
+		}
+
 		/* Copy the first fragment of the record from the first page. */
 		memcpy(state->readRecordBuf,
 			   state->readBuf + RecPtr % XLOG_BLCKSZ, len);
@@ -476,10 +476,8 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
 		if (!ValidXLogRecord(state, record, RecPtr))
 			goto err;
 
-		state->EndRecPtr = RecPtr + MAXALIGN(total_len);
-
 		state->ReadRecPtr = RecPtr;
-		memcpy(state->readRecordBuf, record, total_len);
+		state->EndRecPtr = RecPtr + MAXALIGN(total_len);
 	}
 
 	/*
-- 
2.17.1

#10Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Andrey Lepikhov (#9)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

At Fri, 26 Oct 2018 11:43:14 +0500, Andrey Lepikhov <a.lepikhov@postgrespro.ru> wrote in <ea3dca6a-b898-e7a8-dcfa-b3ad227a6349@postgrespro.ru>

On 26.10.2018 10:33, Kyotaro HORIGUCHI wrote:

Hello.
At Tue, 23 Oct 2018 10:25:27 +0500, Andrey Lepikhov
<a.lepikhov@postgrespro.ru> wrote in
<2553f2b0-0e39-eb0e-d382-6c0ed08ca8ae@postgrespro.ru>

On 23.10.2018 0:53, Heikki Linnakangas wrote:

I'd expect the decompression to read from the on-disk buffer, and
unpack to readRecordBuf, I still don't see a need to copy the packed
record to readRecordBuf. If there is a need for that, though, the
patch that implements the packing or compression can add the memcpy()
where it needs it.

I agree with it. Eventually, placement of the WAL-record can be
defined by comparison the record, readBuf and readRecordBuf pointers.
In attachment new version of the patch.

This looks quite clear and what it does is reasonable to me.
Applies cleanly on top of current master and no regression seen.
Just one comment. This patch leaves the following code.

/* Record does not cross a page boundary */
if (!ValidXLogRecord(state, record, RecPtr))
goto err;

state->EndRecPtr = RecPtr + MAXALIGN(total_len);

!>

state->ReadRecPtr = RecPtr;
}

The empty line (marked by '!') looks a bit too much standing out
after this patch. Could you remove the line? Then could you
transpose the two assignments if you don't mind?

Thanks, see attachment.

Thanks.

This patch eliminates unnecessary copying that was done for
non-continued records. Now the return value of XLogReadRecord
directly points into page buffer holded in XLogReaderStats. It is
safe because no caller site uses the returned pointer beyond the
replacement of buffer content at the next call to the same
function.

The code looks fine and correct.
This applied on HEAD@master cleanly.
Passed all regression tests.
Passed all tests under src/test/recovery

I marked this "Ready for Committer".

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#11Michael Paquier
michael@paquier.xyz
In reply to: Kyotaro HORIGUCHI (#10)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On Thu, Nov 15, 2018 at 06:12:38PM +0900, Kyotaro HORIGUCHI wrote:

This patch eliminates unnecessary copying that was done for
non-continued records. Now the return value of XLogReadRecord
directly points into page buffer holded in XLogReaderStats. It is
safe because no caller site uses the returned pointer beyond the
replacement of buffer content at the next call to the same
function.

I was looking at this patch, and shouldn't we worry about compatibility
with plugins or utilities which look directly at what's in readRecordBuf
for the record contents? Let's not forget that the contents of
XLogReaderState are public.
--
Michael

#12Michael Paquier
michael@paquier.xyz
In reply to: Michael Paquier (#11)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On Fri, Nov 16, 2018 at 03:23:55PM +0900, Michael Paquier wrote:

I was looking at this patch, and shouldn't we worry about compatibility
with plugins or utilities which look directly at what's in readRecordBuf
for the record contents? Let's not forget that the contents of
XLogReaderState are public.

And a couple of days later, committed. I did not notice first that the
comments of xlogreader.h mention that a couple of areas are private, and
readRecordBuf is part of that, so objection withdrawn.

There is a comment in xlog.c (on top of ReadRecord) referring to
readRecordBuf which has not been removed as part of 7fcbf6a4 when WAL
reading has been moved to its own facility. The original comment was
from 0ffe11a. So I have removed the comment at the same time.
--
Michael

#13Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Michael Paquier (#12)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

Thank you for taking this.

At Mon, 19 Nov 2018 10:27:29 +0900, Michael Paquier <michael@paquier.xyz> wrote in <20181119012728.GA1578@paquier.xyz>

On Fri, Nov 16, 2018 at 03:23:55PM +0900, Michael Paquier wrote:

I was looking at this patch, and shouldn't we worry about compatibility
with plugins or utilities which look directly at what's in readRecordBuf
for the record contents? Let's not forget that the contents of
XLogReaderState are public.

And a couple of days later, committed. I did not notice first that the
comments of xlogreader.h mention that a couple of areas are private, and
readRecordBuf is part of that, so objection withdrawn.

It wasn't changed the way the function replaces the content of
the buffer. (Regardless of whether it is private or not, I
believe no one tries to write directly there outside the
function.) Also the memory pointed by the retuned pointer from
the previous code was regarded as read-only. The only point to
notice was the lifetime of the returned pointer, I suppose.

There is a comment in xlog.c (on top of ReadRecord) referring to
readRecordBuf which has not been removed as part of 7fcbf6a4 when WAL
reading has been moved to its own facility. The original comment was
from 0ffe11a. So I have removed the comment at the same time.

- * The record is copied into readRecordBuf, so that on successful return,
- * the returned record pointer always points there.

Yeah, it is incorrect in some sense, but the comment was
suggesting the lifetime of the pointed record. So I'd like to
have a comment like this instead.

+ * The record is copied into xlogreader, so that on successful return,
+ * the returned record pointer always points there.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#14Michael Paquier
michael@paquier.xyz
In reply to: Kyotaro HORIGUCHI (#13)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On Mon, Nov 19, 2018 at 12:28:06PM +0900, Kyotaro HORIGUCHI wrote:

Yeah, it is incorrect in some sense, but the comment was
suggesting the lifetime of the pointed record. So I'd like to
have a comment like this instead.

I think that we can still live without as it is not the business of this
routine to be careful how the lifetime of a record read is handled, but
that's part of the internals of XLogReader.
--
Michael

#15Andrey Lepikhov
a.lepikhov@postgrespro.ru
In reply to: Michael Paquier (#11)
1 attachment(s)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On 16.11.2018 11:23, Michael Paquier wrote:

On Thu, Nov 15, 2018 at 06:12:38PM +0900, Kyotaro HORIGUCHI wrote:

This patch eliminates unnecessary copying that was done for
non-continued records. Now the return value of XLogReadRecord
directly points into page buffer holded in XLogReaderStats. It is
safe because no caller site uses the returned pointer beyond the
replacement of buffer content at the next call to the same
function.

I was looking at this patch, and shouldn't we worry about compatibility
with plugins or utilities which look directly at what's in readRecordBuf
for the record contents? Let's not forget that the contents of
XLogReaderState are public.

According to my experience, I clarify some comments to avoid this
mistakes in the future (see attachment).

--
Andrey Lepikhov
Postgres Professional
https://postgrespro.com
The Russian Postgres Company

Attachments:

0001-Some-clarifications-on-readRecordBuf-comments.patchtext/x-patch; name=0001-Some-clarifications-on-readRecordBuf-comments.patchDownload
From 7de252405ef5d5979fe2711515c0c6402abc0e06 Mon Sep 17 00:00:00 2001
From: "Andrey V. Lepikhov" <a.lepikhov@postgrespro.ru>
Date: Mon, 19 Nov 2018 07:08:28 +0500
Subject: [PATCH] Some clarifications on readRecordBuf comments

---
 src/backend/access/transam/xlogreader.c | 4 ++--
 src/include/access/xlogreader.h         | 6 +++++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index c5e019bf77..88d0bcf48a 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -209,8 +209,8 @@ allocate_recordbuf(XLogReaderState *state, uint32 reclength)
  * If the reading fails for some other reason, NULL is also returned, and
  * *errormsg is set to a string with details of the failure.
  *
- * The returned pointer (or *errormsg) points to an internal buffer that's
- * valid until the next call to XLogReadRecord.
+ * The returned pointer (or *errormsg) points to an internal read-only buffer
+ * that's valid until the next call to XLogReadRecord.
  */
 XLogRecord *
 XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index 40116f8ecb..0837625b95 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -185,7 +185,11 @@ struct XLogReaderState
 	 */
 	TimeLineID	nextTLI;
 
-	/* Buffer for current ReadRecord result (expandable) */
+	/*
+	 * Buffer for current ReadRecord result (expandable).
+	 * Used in the case, than current ReadRecord result don't fit on the
+	 * currently read WAL page.
+	 */
 	char	   *readRecordBuf;
 	uint32		readRecordBufSize;
 
-- 
2.17.1

#16Michael Paquier
michael@paquier.xyz
In reply to: Andrey Lepikhov (#15)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On Mon, Nov 19, 2018 at 10:48:06AM +0500, Andrey Lepikhov wrote:

According to my experience, I clarify some comments to avoid this mistakes
in the future (see attachment).

No objections from here.

- * The returned pointer (or *errormsg) points to an internal buffer that's
- * valid until the next call to XLogReadRecord.
+ * The returned pointer (or *errormsg) points to an internal read-only buffer
+ * that's valid until the next call to XLogReadRecord.

Not sure that this bit adds much.

-	/* Buffer for current ReadRecord result (expandable) */
+	/*
+	 * Buffer for current ReadRecord result (expandable).
+	 * Used in the case, than current ReadRecord result don't fit on the
+	 * currently read WAL page.
+	 */
Yeah, this one is not entirely true now.  What about the following
instead:
-   /* Buffer for current ReadRecord result (expandable) */
+   /*
+    * Buffer for current ReadRecord result (expandable), used when a record
+    * crosses a page boundary.
+    */
--
Michael
#17Andrey Lepikhov
a.lepikhov@postgrespro.ru
In reply to: Michael Paquier (#16)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On 20.11.2018 6:30, Michael Paquier wrote:

On Mon, Nov 19, 2018 at 10:48:06AM +0500, Andrey Lepikhov wrote:

According to my experience, I clarify some comments to avoid this mistakes
in the future (see attachment).

No objections from here.

- * The returned pointer (or *errormsg) points to an internal buffer that's
- * valid until the next call to XLogReadRecord.
+ * The returned pointer (or *errormsg) points to an internal read-only buffer
+ * that's valid until the next call to XLogReadRecord.

Not sure that this bit adds much.

Ok

-	/* Buffer for current ReadRecord result (expandable) */
+	/*
+	 * Buffer for current ReadRecord result (expandable).
+	 * Used in the case, than current ReadRecord result don't fit on the
+	 * currently read WAL page.
+	 */
Yeah, this one is not entirely true now.  What about the following
instead:
-   /* Buffer for current ReadRecord result (expandable) */
+   /*
+    * Buffer for current ReadRecord result (expandable), used when a record
+    * crosses a page boundary.
+    */

I agree

--
Andrey Lepikhov
Postgres Professional
https://postgrespro.com
The Russian Postgres Company

#18Michael Paquier
michael@paquier.xyz
In reply to: Andrey Lepikhov (#17)
Re: [PATCH] XLogReadRecord returns pointer to currently read page

On Tue, Nov 20, 2018 at 06:37:36AM +0500, Andrey Lepikhov wrote:

On 20.11.2018 6:30, Michael Paquier wrote:

Yeah, this one is not entirely true now.  What about the following
instead:
-   /* Buffer for current ReadRecord result (expandable) */
+   /*
+    * Buffer for current ReadRecord result (expandable), used when a record
+    * crosses a page boundary.
+    */

I agree

Okay, I have committed this version, after checking that there were no
other spots.
--
Michael