pg_stat_database.checksum_failures vs shared relations
Hi,
First - I find it rather shocking that we have absolutely *zero* tests of
checksum failures in the backend. Zero. As evidenced by [1]https://coverage.postgresql.org/src/backend/storage/page/bufpage.c.gcov.html#136. I really can't
quite believe it. Nor do we have tests of ignore_checksum_failure or
zero_damaged_pages.
I was trying to write some tests for checksums vs AIO, and one thing I noticed
is that our docs seem to rather strongly hint that checksum failures on shared
objects would be reported to the dbname IS NULL row in pg_stat_database:
The <structname>pg_stat_database</structname> view will contain one row
for each database in the cluster, plus one for shared objects, showing
database-wide statistics.
Name of this database, or <literal>NULL</literal> for shared
objects.
Number of data page checksum failures detected in this
database (or on a shared object), or NULL if data checksums are
disabled.
But that is not the case, they always get reported to MyDatabaseId by
PageIsVerifiedExtended().
The docs hint more clearly at checksum failures of shared rels reported this
way starting with:
commit 252b707bc41
Author: Magnus Hagander <magnus@hagander.net>
Date: 2019-04-17 13:51:48 +0200
Return NULL for checksum failures if checksums are not enabled
which made changes like:
<entry>Number of data page checksum failures detected in this
- database</entry>
+ database (or on a shared object), or NULL if data checksums are not
+ enabled.</entry>
</row>
The stats tracking of checksum failures was introduced in
Author: Magnus Hagander <magnus@hagander.net>
Date: 2019-03-09 10:45:17 -0800
Track block level checksum failures in pg_stat_database
which already did report stats on shared objects that way:
@@ -151,6 +152,8 @@ PageIsVerified(Page page, BlockNumber blkno)
errmsg("page verification failed, calculated checksum %u but expected %u",
checksum, p->pd_checksum)));
+ pgstat_report_checksum_failure();
+
if (header_sane && ignore_checksum_failure)
return true;
}
In basebackup.c however, it didn't track stats on shared relations at that time:
@@ -1580,6 +1583,9 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
ereport(WARNING,
(errmsg("file \"%s\" has a total of %d checksum verification "
"failures", readfilename, checksum_failures)));
+
+ if (dboid != InvalidOid)
+ pgstat_report_checksum_failures_in_db(dboid, checksum_failures);
}
total_checksum_failures += checksum_failures;
that was changed in:
commit 77bd49adba4
Author: Magnus Hagander <magnus@hagander.net>
Date: 2019-04-12 14:04:50 +0200
Show shared object statistics in pg_stat_database
This adds a row to the pg_stat_database view with datoid 0 and datname
NULL for those objects that are not in a database. This was added
particularly for checksums, but we were already tracking more satistics
for these objects, just not returning it.
...
which made the call to pgstat_report_checksum_failures_in_db()
in basebackup.c unconditional. It did leave this comment though:
* If dboid is anything other than InvalidOid then any checksum failures
* detected will get reported to the cumulative stats system.
I think the above commit makes it pretty clear that the intent is for checksum
errors on shared database entries to be reported to the "shared" entry in
pg_stat_database.
So, today we have the weird situation that *some* checksum errors on shared
relations get attributed to the current database (if they happen in a backend
normally accessing a shared relation), whereas others get reported to the
"shared relations" "database" (if they happen during a base backup). That
seems ... not optimal.
One question is whether we consider this a bug that should be backpatched.
To fix it we'd need to provide a bit more information to
PageIsVerifiedExtended(), it currently doesn't know what database the page it
is verifying is in and therefore can't report an error with
pgstat_report_checksum_failures_in_db() (rather than
pgstat_report_checksum_failure(), which attributes to MyDatabaseId).
Obviously having to change the signature of PageIsVerifiedExtended() makes it
harder to fix in the backbranches.
Greetings,
Andres Freund
[1]: https://coverage.postgresql.org/src/backend/storage/page/bufpage.c.gcov.html#136
On Thu, Mar 27, 2025 at 11:58 AM Andres Freund <andres@anarazel.de> wrote:
So, today we have the weird situation that *some* checksum errors on shared
relations get attributed to the current database (if they happen in a backend
normally accessing a shared relation), whereas others get reported to the
"shared relations" "database" (if they happen during a base backup). That
seems ... not optimal.One question is whether we consider this a bug that should be backpatched.
I think it would be defensible if pg_basebackup reported all errors
with OID 0 and backend connections reported all errors with OID
MyDatabaseId, but it seems hard to justify having pg_basebackup take
care to report things using the correct database OID and individual
backend connections not take care to do the same thing. So I think
this is a bug. If fixing it in the back-branches is too annoying, I
think it would be reasonable to fix it only in master, but
back-patching seems OK too.
--
Robert Haas
EDB: http://www.enterprisedb.com
On Thu, Mar 27, 2025 at 12:06:45PM -0400, Robert Haas wrote:
On Thu, Mar 27, 2025 at 11:58 AM Andres Freund <andres@anarazel.de> wrote:
So, today we have the weird situation that *some* checksum errors on shared
relations get attributed to the current database (if they happen in a backend
normally accessing a shared relation), whereas others get reported to the
"shared relations" "database" (if they happen during a base backup). That
seems ... not optimal.One question is whether we consider this a bug that should be backpatched.
I think it would be defensible if pg_basebackup reported all errors
with OID 0 and backend connections reported all errors with OID
MyDatabaseId, but it seems hard to justify having pg_basebackup take
care to report things using the correct database OID and individual
backend connections not take care to do the same thing. So I think
this is a bug. If fixing it in the back-branches is too annoying, I
think it would be reasonable to fix it only in master, but
back-patching seems OK too.
Being able to get a better reporting for shared relations in back
branches would be nice, but that's going to require some invasive
chirurgy, isn't it?
We don't know currently the OID of the relation whose block is
corrupted with only PageIsVerifiedExtended(). There are two callers
of PIV_REPORT_STAT on HEAD:
- The checksum reports from RelationCopyStorage() know the
SMgrRelation.
- ReadBuffersOperation() has an optional Relation and a
SMgrRelationData.
We could just refactor PageIsVerifiedExtended() so as it reports a
state about why the verification failed and let the callers report the
checksum failure with a relation OID, splitting the data for shared
and non-shared relations?
--
Michael
Hi,
On 2025-03-28 09:44:58 +0900, Michael Paquier wrote:
On Thu, Mar 27, 2025 at 12:06:45PM -0400, Robert Haas wrote:
On Thu, Mar 27, 2025 at 11:58 AM Andres Freund <andres@anarazel.de> wrote:
So, today we have the weird situation that *some* checksum errors on shared
relations get attributed to the current database (if they happen in a backend
normally accessing a shared relation), whereas others get reported to the
"shared relations" "database" (if they happen during a base backup). That
seems ... not optimal.One question is whether we consider this a bug that should be backpatched.
I think it would be defensible if pg_basebackup reported all errors
with OID 0 and backend connections reported all errors with OID
MyDatabaseId, but it seems hard to justify having pg_basebackup take
care to report things using the correct database OID and individual
backend connections not take care to do the same thing. So I think
this is a bug. If fixing it in the back-branches is too annoying, I
think it would be reasonable to fix it only in master, but
back-patching seems OK too.Being able to get a better reporting for shared relations in back
branches would be nice, but that's going to require some invasive
chirurgy, isn't it?
Yea, that's what I was worried about too. I think we basically would need a
PageIsVerifiedExtended2() that backs the current PageIsVerifiedExtended(),
with optional arguments that the "fixed" callers would use.
We don't know currently the OID of the relation whose block is
corrupted with only PageIsVerifiedExtended().
I don't think the relation oid is really the relevant bit, it's the database
oid (or alternatively tablespace). But PageIsVerifiedExtended() doesn't know
that either, obviously.
There are two callers of PIV_REPORT_STAT on HEAD:
- The checksum reports from RelationCopyStorage() know the
SMgrRelation.
- ReadBuffersOperation() has an optional Relation and a
SMgrRelationData.
An SMgrRelationData suffices, via ->smgr_rlocator.locator.dbOid.
FWIW, it turns out that there are more cases than just MyDatabaseId and
InvalidOid - ScanSourceDatabasePgClass() and RelationCopyStorageUsingBuffer()
read buffers in a different database than MyDatabaseId.
We could just refactor PageIsVerifiedExtended() so as it reports a
state about why the verification failed and let the callers report the
checksum failure with a relation OID, splitting the data for shared
and non-shared relations?
Yea, I think we basically need a *checksum_failed out argument, and then the
callers need to do
if (checksum_failure)
pgstat_report_checksum_failures_in_db(src->smgr_rlocator.locator.dbOid, 1);
Or alternatively we can optionally pass in the rlocator to
PageIsVerifiedExtended2(), so it can do the above internally.
Btw, it seems somewhat odd that we accumulate stats for checksum failures but
not for invalid page headers - the latter seems even worse...
Greetings,
Andres Freund
On Thu, Mar 27, 2025 at 09:02:02PM -0400, Andres Freund wrote:
Hi,
On 2025-03-28 09:44:58 +0900, Michael Paquier wrote:
On Thu, Mar 27, 2025 at 12:06:45PM -0400, Robert Haas wrote:
On Thu, Mar 27, 2025 at 11:58 AM Andres Freund <andres@anarazel.de> wrote:
So, today we have the weird situation that *some* checksum errors on shared
relations get attributed to the current database (if they happen in a backend
normally accessing a shared relation), whereas others get reported to the
"shared relations" "database" (if they happen during a base backup). That
seems ... not optimal.One question is whether we consider this a bug that should be backpatched.
I think it would be defensible if pg_basebackup reported all errors
with OID 0 and backend connections reported all errors with OID
MyDatabaseId, but it seems hard to justify having pg_basebackup take
care to report things using the correct database OID and individual
backend connections not take care to do the same thing. So I think
this is a bug. If fixing it in the back-branches is too annoying, I
think it would be reasonable to fix it only in master, but
back-patching seems OK too.Being able to get a better reporting for shared relations in back
branches would be nice, but that's going to require some invasive
chirurgy, isn't it?Yea, that's what I was worried about too. I think we basically would need a
PageIsVerifiedExtended2() that backs the current PageIsVerifiedExtended(),
with optional arguments that the "fixed" callers would use.
While it would be nice, I'm not sure that it would really be worth the trouble.
Maybe that's just me, but if I hit a corruption failure knowing whether it's a
global relation vs normal relation is definitely not something that will
radically change the following days / weeks of pain to fully resolve the
issue. Instead there would be other improvements that I would welcome on top
of fixing those counters, which would impact such new API.
For instance one of the thing you need to do in case of a corruption is to
understand the reason for the corruption, and for that knowing the underlying
tablespace rather than the database seems like a way more useful information to
track. For the rest, the relfilelocator, forknum and blocknum should already
be reported in the logs so you have the full details of what was intercepted
even if the pg_stat_database view is broken in the back branches.
But even if we had all that, there is still no guarantee (at least for now)
that we do see all the corruption as you might not read the "real" version of
the blockss if they are in shared buffers and/or in the OS cache, depending on
where the corruption actually happened.
And even if you could actually check what is physically stored on disk, that
would probably won't give you any strong guarantee that the rest data is
actually ok anyway. The biggest source of corruption I know is an old vmware
bug usually referred as the SEsparse bug, where in some occasion some blocks
would get written at the wrong location. In that case, the checksum can tell
me which are the blocks where the wrong write happened, but not what are the
blocks where the write should have happened, which are also entirely
inconsistent too. That's clearly out of postgres scope, but that's in my
opinion just one out of probably a lot more examples that makes the current bug
in back branches not worth spending too many efforts to fix.
Hi,
Attached is a fix for the issue.
I looked around and didn't find extensions using PageIsVerified[Extended]() in
codesearch.debian.org, so I got rid of the compat macro and renamed
PageIsVerifiedExtended back to PageIsVerified().
Normally I'd commit tests as part of a fix like this, but since I've already
written test infrastructure for checksum failures and their stats as part of
aio, and those tests don't work without more of aio applied, I don't think it
makes sense to write them for just this test. It's not like anybody has ever
bothered to test checksum failures before...
Greetings,
Andres Freund
Attachments:
0001-Fix-mis-attribution-of-checksum-failure-stats-to-the.patchtext/x-diff; charset=us-asciiDownload
From 24d9e2454662dfda73f2b519368ff7a96ef15f65 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Fri, 28 Mar 2025 12:29:40 -0400
Subject: [PATCH] Fix mis-attribution of checksum failure stats to the wrong
database
Checksum failure stats could be attributed to the wrong database in two cases:
- when a read of a shared relation encountered a checksum error , it would be
attributed to the current database, instead of the "database" representing
shared relations
- when using CREATE DATABASE ... STRATEGY WAL_LOG checksum errors in the
source database would be attributed to the current database
The checksum stats reporting via PageIsVerifiedExtended(PIV_REPORT_STAT) does
not have access to the information about what database a page belongs to.
This fixes the issue by removing PIV_REPORT_STAT and delegating the
responsibility to report stats to the caller, which now can learn about the
number of stats via a new optional argument.
As this changes the signature of PageIsVerifiedExtended() and all callers
should adapt to the new signature, use the occasion to rename the function to
PageIsVerified() and remove the compatibility macro.
We could instead have fixed this by adding information about the database to
the args of PageIsVerified(), but there are soon-to-be-applied patches that
need to separate the stats reporting from the PageIsVerified() call
anyway. Those patches also include testing for the failure paths, something we
inexplicably have not had.
As there is no caller of pgstat_report_checksum_failure() left, remove it.
It'd be possible, but awkward to fix this in the back branches. We considered
doing the work not quite worth it, as mis-attributed stats should still elicit
concern. The emitted error messages do allow to attribute the errors
correctly.
Discussion: https://postgr.es/m/5tyic6epvdlmd6eddgelv47syg2b5cpwffjam54axp25xyq2ga@ptwkinxqo3az
Discussion: https://postgr.es/m/mglpvvbhighzuwudjxzu4br65qqcxsnyvio3nl4fbog3qknwhg@e4gt7npsohuz
---
src/include/pgstat.h | 1 -
src/include/storage/bufpage.h | 20 ++++++++------------
src/backend/catalog/storage.c | 16 ++++++++++++++--
src/backend/storage/buffer/bufmgr.c | 16 +++++++++++++---
src/backend/storage/page/bufpage.c | 20 +++++++++++++-------
src/backend/utils/activity/pgstat_database.c | 9 ---------
6 files changed, 48 insertions(+), 34 deletions(-)
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 5bfe19e66be..9f3d13bf1ce 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -612,7 +612,6 @@ extern void pgstat_report_autovac(Oid dboid);
extern void pgstat_report_recovery_conflict(int reason);
extern void pgstat_report_deadlock(void);
extern void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount);
-extern void pgstat_report_checksum_failure(void);
extern void pgstat_report_connect(Oid dboid);
extern void pgstat_update_parallel_workers_stats(PgStat_Counter workers_to_launch,
PgStat_Counter workers_launched);
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index 6646b6f6371..b943db707db 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -465,31 +465,27 @@ do { \
#define PAI_OVERWRITE (1 << 0)
#define PAI_IS_HEAP (1 << 1)
-/* flags for PageIsVerifiedExtended() */
+/* flags for PageIsVerified() */
#define PIV_LOG_WARNING (1 << 0)
-#define PIV_REPORT_STAT (1 << 1)
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap) \
PageAddItemExtended(page, item, size, offsetNumber, \
((overwrite) ? PAI_OVERWRITE : 0) | \
((is_heap) ? PAI_IS_HEAP : 0))
-#define PageIsVerified(page, blkno) \
- PageIsVerifiedExtended(page, blkno, \
- PIV_LOG_WARNING | PIV_REPORT_STAT)
-
/*
- * Check that BLCKSZ is a multiple of sizeof(size_t). In
- * PageIsVerifiedExtended(), it is much faster to check if a page is
- * full of zeroes using the native word size. Note that this assertion
- * is kept within a header to make sure that StaticAssertDecl() works
- * across various combinations of platforms and compilers.
+ * Check that BLCKSZ is a multiple of sizeof(size_t). In PageIsVerified(), it
+ * is much faster to check if a page is full of zeroes using the native word
+ * size. Note that this assertion is kept within a header to make sure that
+ * StaticAssertDecl() works across various combinations of platforms and
+ * compilers.
*/
StaticAssertDecl(BLCKSZ == ((BLCKSZ / sizeof(size_t)) * sizeof(size_t)),
"BLCKSZ has to be a multiple of sizeof(size_t)");
extern void PageInit(Page page, Size pageSize, Size specialSize);
-extern bool PageIsVerifiedExtended(PageData *page, BlockNumber blkno, int flags);
+extern bool PageIsVerified(PageData *page, BlockNumber blkno, int flags,
+ bool *checksum_failure_p);
extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size,
OffsetNumber offsetNumber, int flags);
extern Page PageGetTempPage(const PageData *page);
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index 624ed41bbf3..cacf16c1cdb 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -27,6 +27,7 @@
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "storage/bulk_write.h"
#include "storage/freespace.h"
#include "storage/proc.h"
@@ -507,6 +508,8 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
for (blkno = 0; blkno < nblocks; blkno++)
{
BulkWriteBuffer buf;
+ bool checksum_failure;
+ bool verified;
/* If we got a cancel signal during the copy of the data, quit */
CHECK_FOR_INTERRUPTS();
@@ -514,8 +517,17 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
buf = smgr_bulk_get_buf(bulkstate);
smgrread(src, forkNum, blkno, (Page) buf);
- if (!PageIsVerifiedExtended((Page) buf, blkno,
- PIV_LOG_WARNING | PIV_REPORT_STAT))
+ verified = PageIsVerified((Page) buf, blkno, PIV_LOG_WARNING,
+ &checksum_failure);
+
+ if (checksum_failure)
+ {
+ RelFileLocatorBackend rloc = src->smgr_rlocator;
+
+ pgstat_report_checksum_failures_in_db(rloc.locator.dbOid, 1);
+ }
+
+ if (!verified)
{
/*
* For paranoia's sake, capture the file path before invoking the
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 323382dcfa8..5cac8cd7389 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -770,7 +770,7 @@ ReadBuffer(Relation reln, BlockNumber blockNum)
* In RBM_NORMAL mode, the page is read from disk, and the page header is
* validated. An error is thrown if the page header is not valid. (But
* note that an all-zero page is considered "valid"; see
- * PageIsVerifiedExtended().)
+ * PageIsVerified().)
*
* RBM_ZERO_ON_ERROR is like the normal mode, but if the page header is not
* valid, the page is zeroed instead of throwing an error. This is intended
@@ -1569,6 +1569,8 @@ WaitReadBuffers(ReadBuffersOperation *operation)
{
BufferDesc *bufHdr;
Block bufBlock;
+ bool verified;
+ bool checksum_failure;
if (persistence == RELPERSISTENCE_TEMP)
{
@@ -1582,8 +1584,16 @@ WaitReadBuffers(ReadBuffersOperation *operation)
}
/* check for garbage data */
- if (!PageIsVerifiedExtended((Page) bufBlock, io_first_block + j,
- PIV_LOG_WARNING | PIV_REPORT_STAT))
+ verified = PageIsVerified((Page) bufBlock, io_first_block + j,
+ PIV_LOG_WARNING, &checksum_failure);
+ if (checksum_failure)
+ {
+ RelFileLocatorBackend rloc = operation->smgr->smgr_rlocator;
+
+ pgstat_report_checksum_failures_in_db(rloc.locator.dbOid, 1);
+ }
+
+ if (!verified)
{
if ((operation->flags & READ_BUFFERS_ZERO_ON_ERROR) || zero_damaged_pages)
{
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index ecc81aacfc3..5d1b039fcbb 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -61,7 +61,7 @@ PageInit(Page page, Size pageSize, Size specialSize)
/*
- * PageIsVerifiedExtended
+ * PageIsVerified
* Check that the page header and checksum (if any) appear valid.
*
* This is called when a page has just been read in from disk. The idea is
@@ -81,11 +81,13 @@ PageInit(Page page, Size pageSize, Size specialSize)
* If flag PIV_LOG_WARNING is set, a WARNING is logged in the event of
* a checksum failure.
*
- * If flag PIV_REPORT_STAT is set, a checksum failure is reported directly
- * to pgstat.
+ * To allow the caller to report statistics about checksum failures,
+ * *checksum_failure_p can be passed in. Note that there may be checksum
+ * failures even if this function returns true, due to
+ * ignore_checksum_failure.
*/
bool
-PageIsVerifiedExtended(PageData *page, BlockNumber blkno, int flags)
+PageIsVerified(PageData *page, BlockNumber blkno, int flags, bool *checksum_failure_p)
{
const PageHeaderData *p = (const PageHeaderData *) page;
size_t *pagebytes;
@@ -93,6 +95,9 @@ PageIsVerifiedExtended(PageData *page, BlockNumber blkno, int flags)
bool header_sane = false;
uint16 checksum = 0;
+ if (checksum_failure_p)
+ *checksum_failure_p = false;
+
/*
* Don't verify page data unless the page passes basic non-zero test
*/
@@ -103,7 +108,11 @@ PageIsVerifiedExtended(PageData *page, BlockNumber blkno, int flags)
checksum = pg_checksum_page(page, blkno);
if (checksum != p->pd_checksum)
+ {
checksum_failure = true;
+ if (checksum_failure_p)
+ *checksum_failure_p = true;
+ }
}
/*
@@ -141,9 +150,6 @@ PageIsVerifiedExtended(PageData *page, BlockNumber blkno, int flags)
errmsg("page verification failed, calculated checksum %u but expected %u",
checksum, p->pd_checksum)));
- if ((flags & PIV_REPORT_STAT) != 0)
- pgstat_report_checksum_failure();
-
if (header_sane && ignore_checksum_failure)
return true;
}
diff --git a/src/backend/utils/activity/pgstat_database.c b/src/backend/utils/activity/pgstat_database.c
index 05a8ccfdb75..c0c02efd9d3 100644
--- a/src/backend/utils/activity/pgstat_database.c
+++ b/src/backend/utils/activity/pgstat_database.c
@@ -159,15 +159,6 @@ pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount)
pgstat_unlock_entry(entry_ref);
}
-/*
- * Report one checksum failure in the current database.
- */
-void
-pgstat_report_checksum_failure(void)
-{
- pgstat_report_checksum_failures_in_db(MyDatabaseId, 1);
-}
-
/*
* Report creation of temporary file.
*/
--
2.48.1.76.g4e746b1a31.dirty
Hi,
On 2025-03-28 13:47:16 -0400, Andres Freund wrote:
Attached is a fix for the issue.
I plan to push this fix soon, unless somebody protests...
Greetings,
Andres Freund
Hi,
On 2025-03-29 13:17:44 -0400, Andres Freund wrote:
On 2025-03-28 13:47:16 -0400, Andres Freund wrote:
Attached is a fix for the issue.
I plan to push this fix soon, unless somebody protests...
And done.
Greetings,
Andres Freund
On Sat, Mar 29, 2025 at 7:09 PM Andres Freund <andres@anarazel.de> wrote:
Hi,
On 2025-03-29 13:17:44 -0400, Andres Freund wrote:
On 2025-03-28 13:47:16 -0400, Andres Freund wrote:
Attached is a fix for the issue.
I plan to push this fix soon, unless somebody protests...
And done.
Hi!
Sorry to get into this thread a bit late. Just to let you know that now
that I'm caught up, I do agree it looks right.
And - thanks for handling this!
//Magnus