27.03.2026 21:30, Yura Sokolov пишет:
> Good day,
>
> 27.03.2026 12:04, Yura Sokolov wrote:
>> 26.03.2026 23:29, Andres Freund wrote:
>>> Hi,
>>>
>>> On 2026-03-25 17:51:30 +0300, Yura Sokolov wrote:
>>>> UnlockBufHdrExt does:
>>>>
>>>> buf_state |= set_bits;
>>>> buf_state &= ~unset_bits;
>>>> buf_state &= ~BM_LOCKED;
>>>>
>>>> TerminateBufferIO unconditionally does:
>>>>
>>>> unset_flag_bits |= BM_IO_ERROR;
>>>>
>>>> Due to this, AbortBufferIO and buffer_readv_complete_one are failed
>>>> to set BM_IO_ERROR with call to TerminateBufferIO.
>>>>
>>>> It was found with proprietary code that was triggered on
>>>> PGAIO_RS_ERROR and made assertion on BM_IO_ERROR presence.
>>>
>>> That's clearly not right. Care to write a patch? I think we should add a
>>> test for this in src/test/modules/test_aio too. As we don't rely on things
>>> like BM_IO_ERROR this is quite easy to not notice.
>> I thought, fix is too small to go the way of patches.
>> I don't mind if you just push it.
>>
>> But if I can save your time on writing test, I'll try.
>>
>> ...
>>
>> I believe, proper way is to add assertion in UnlockBufHdrExt:
>>
>> Assert(!(set_bits & unset_bits));
>>
>> And make TerminateBufferIO to exclude BM_IO_ERROR if it is among
>> set_flag_bits.
>>
>> Is it ok?
>
> Here patchset is.
>
> I've tried to modify 001_aio.pl to test presence BM_IO_ERROR after read
> failure.
>
> I've also added FlushBuffer failure test in second patch (v1-002) using
> injection point. I don't know if 001-aio.pl is a good place for since write
> is not async yet.
>
> v1-003 just mades DebugPrintBufferRefcount prettier.
rebased.
--
regards
Yura Sokolov aka funny-falcon
From 5cbaa035027d4f6c57d561ca4f9c5161f7a49471 Mon Sep 17 00:00:00 2001
From: Yura Sokolov <[email protected]>
Date: Fri, 27 Mar 2026 20:11:06 +0300
Subject: [PATCH v2 1/3] bufmgr: Fix possibility to set BM_IO_ERROR
Previously it couldn't be set because TerminateBufferIO added BM_IO_ERROR
to unset_flag_bits unconditionally, and UnlockBufHdrExt applied unset_bits
after set_bits.
Fix by not setting BM_IO_ERROR into unset_flag_bits if it is present in
set_flag_bits.
Also protect from possible similar errors by adding assertion to
UnlockBufHdrExt unset_bits and set_bits have no bits in common.
Modify src/test/modules/test_aio/t/001_aio.pl test_io_error to check
presence of BM_IO_ERROR.
---
src/backend/storage/buffer/bufmgr.c | 4 +--
src/include/storage/buf_internals.h | 1 +
src/test/modules/test_aio/t/001_aio.pl | 20 ++++++++++++++
src/test/modules/test_aio/test_aio--1.0.sql | 4 +++
src/test/modules/test_aio/test_aio.c | 30 +++++++++++++++++++++
5 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index cd21ae3fc36..a81949aca7c 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -7347,8 +7347,8 @@ TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits,
Assert(buf_state & BM_IO_IN_PROGRESS);
unset_flag_bits |= BM_IO_IN_PROGRESS;
- /* Clear earlier errors, if this IO failed, it'll be marked again */
- unset_flag_bits |= BM_IO_ERROR;
+ /* Clear earlier errors, unless this IO failed as well */
+ unset_flag_bits |= BM_IO_ERROR & ~set_flag_bits;
if (clear_dirty)
unset_flag_bits |= BM_DIRTY | BM_CHECKPOINT_NEEDED;
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index ad1b7b2216a..93887cea46d 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -475,6 +475,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state,
uint64 set_bits, uint64 unset_bits,
int refcount_change)
{
+ Assert(!(set_bits & unset_bits));
for (;;)
{
uint64 buf_state = old_buf_state;
diff --git a/src/test/modules/test_aio/t/001_aio.pl b/src/test/modules/test_aio/t/001_aio.pl
index 63cadd64c15..a48b0ddfba8 100644
--- a/src/test/modules/test_aio/t/001_aio.pl
+++ b/src/test/modules/test_aio/t/001_aio.pl
@@ -344,6 +344,8 @@ SELECT modify_rel_block('tmp_corr', 1, corrupt_header=>true);
$tblname eq 'tbl_corr'
? qr/invalid page in block 1 of relation "base\/\d+\/\d+/
: qr/invalid page in block 1 of relation "base\/\d+\/t\d+_\d+/;
+ # BM_IO_ERROR and BM_TAG_VALID should be set
+ my $debug_print_re = qr/blockNum=1, flags=0x.?a000000, refcount=0/;
# verify the error is reported in custom C code
psql_like(
@@ -354,6 +356,12 @@ SELECT modify_rel_block('tmp_corr', 1, corrupt_header=>true);
qr/^$/,
$invalid_page_re);
+ psql_like(
+ $io_method, $psql,
+ "validate flags of $tblname page after read_rel_block_ll()",
+ qq(SELECT debug_print_rel_block('$tblname', 1)),
+ $debug_print_re, qr/^$/);
+
# verify the error is reported for bufmgr reads, seq scan
psql_like(
$io_method, $psql,
@@ -361,6 +369,12 @@ SELECT modify_rel_block('tmp_corr', 1, corrupt_header=>true);
qq(SELECT count(*) FROM $tblname),
qr/^$/, $invalid_page_re);
+ psql_like(
+ $io_method, $psql,
+ "validate flags of $tblname page after read_rel_block_ll()",
+ qq(SELECT debug_print_rel_block('$tblname', 1)),
+ $debug_print_re, qr/^$/);
+
# verify the error is reported for bufmgr reads, tid scan
psql_like(
$io_method,
@@ -369,6 +383,12 @@ SELECT modify_rel_block('tmp_corr', 1, corrupt_header=>true);
qq(SELECT count(*) FROM $tblname WHERE ctid = '(1, 1)'),
qr/^$/,
$invalid_page_re);
+
+ psql_like(
+ $io_method, $psql,
+ "validate flags of $tblname page after read_rel_block_ll()",
+ qq(SELECT debug_print_rel_block('$tblname', 1)),
+ $debug_print_re, qr/^$/);
}
$psql->quit();
diff --git a/src/test/modules/test_aio/test_aio--1.0.sql b/src/test/modules/test_aio/test_aio--1.0.sql
index 762ac29512f..cb168e2e08f 100644
--- a/src/test/modules/test_aio/test_aio--1.0.sql
+++ b/src/test/modules/test_aio/test_aio--1.0.sql
@@ -37,6 +37,10 @@ CREATE FUNCTION evict_rel(rel regclass)
RETURNS pg_catalog.void STRICT
AS 'MODULE_PATHNAME' LANGUAGE C;
+CREATE FUNCTION debug_print_rel_block(rel regclass, blockno int)
+RETURNS pg_catalog.text STRICT
+AS 'MODULE_PATHNAME' LANGUAGE C;
+
CREATE FUNCTION invalidate_rel_block(rel regclass, blockno int)
RETURNS pg_catalog.void STRICT
AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c
index a8267192cb7..a89cbd5786d 100644
--- a/src/test/modules/test_aio/test_aio.c
+++ b/src/test/modules/test_aio/test_aio.c
@@ -597,6 +597,36 @@ evict_rel(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+PG_FUNCTION_INFO_V1(debug_print_rel_block);
+Datum
+debug_print_rel_block(PG_FUNCTION_ARGS)
+{
+ Oid relid = PG_GETARG_OID(0);
+ BlockNumber blkno = PG_GETARG_UINT32(1);
+ Relation rel;
+ PrefetchBufferResult pr;
+ Buffer buf;
+ char *desc = NULL;
+
+ rel = relation_open(relid, AccessExclusiveLock);
+
+ /*
+ * This is a gross hack, but there's no other API exposed that allows to
+ * get a buffer ID without actually reading the block in.
+ */
+ pr = PrefetchBuffer(rel, MAIN_FORKNUM, blkno);
+ buf = pr.recent_buffer;
+
+ if (BufferIsValid(buf))
+ desc = DebugPrintBufferRefcount(buf);
+
+ relation_close(rel, AccessExclusiveLock);
+
+ if (desc == NULL)
+ PG_RETURN_NULL();
+ PG_RETURN_TEXT_P(cstring_to_text(desc));
+}
+
PG_FUNCTION_INFO_V1(buffer_create_toy);
Datum
buffer_create_toy(PG_FUNCTION_ARGS)
--
2.51.0
From 13d47451a0532d123bdac4afb7b18a2c045ba441 Mon Sep 17 00:00:00 2001
From: Yura Sokolov <[email protected]>
Date: Fri, 27 Mar 2026 20:55:24 +0300
Subject: [PATCH v2 2/3] bufmgr: Add test for BM_IO_ERROR presence after write
error in FlushBuffer
smgrwrite should raise error on mdwrite error. Lets immitate it with
injection point.
Check BM_IO_ERROR is set and second attempt leads to "Multiple failures"
warning.
---
src/backend/storage/buffer/bufmgr.c | 2 +
src/test/modules/test_aio/t/001_aio.pl | 27 ++++++++++
src/test/modules/test_aio/test_aio--1.0.sql | 11 +++-
src/test/modules/test_aio/test_aio.c | 58 +++++++++++++++++++--
4 files changed, 94 insertions(+), 4 deletions(-)
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index a81949aca7c..fd12566e674 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -64,6 +64,7 @@
#include "storage/read_stream.h"
#include "storage/smgr.h"
#include "storage/standby.h"
+#include "utils/injection_point.h"
#include "utils/memdebug.h"
#include "utils/ps_status.h"
#include "utils/rel.h"
@@ -4560,6 +4561,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object,
bufBlock,
false);
+ INJECTION_POINT("flush-buffer-after-smgr-write", buf);
/*
* When a strategy is in use, only flushes of dirty buffers already in the
* strategy ring are counted as strategy writes (IOCONTEXT
diff --git a/src/test/modules/test_aio/t/001_aio.pl b/src/test/modules/test_aio/t/001_aio.pl
index a48b0ddfba8..54061e0425b 100644
--- a/src/test/modules/test_aio/t/001_aio.pl
+++ b/src/test/modules/test_aio/t/001_aio.pl
@@ -818,6 +818,33 @@ SELECT invalidate_rel_block('tbl_ok', 2);
);
$psql->query_safe(qq(SELECT inj_io_short_read_detach()));
+ # Now test write error
+ $psql->query_safe("SELECT count(*) FROM tbl_ok");
+ $psql->query_safe("SELECT inj_io_error_flush_buffer_attach();");
+ psql_like(
+ $io_method, $psql,
+ "flush error is reported",
+ qq(SELECT invalidate_rel_block('tbl_ok', 2, force_flush=>true)),
+ qr/^$/,
+ qr/ERROR:.*injection point triggering failure to flush buffer/
+ );
+ # BM_IO_ERROR, BM_VALID and BM_TAG_VALID should be set
+ psql_like(
+ $io_method, $psql,
+ "validate flags of 'tbl_ok' page after read_rel_block_ll()",
+ qq(SELECT debug_print_rel_block('tbl_ok', 2)),
+ qr/blockNum=2, flags=0x.?b.00000, refcount=0/, qr/^$/);
+ # Validate second attempt leads to "Multiple failures" message
+ psql_like(
+ $io_method, $psql,
+ "flush error is reported",
+ qq(SELECT invalidate_rel_block('tbl_ok', 2, force_flush=>true)),
+ qr/^$/,
+ qr/Multiple failures --- write error might be permanent/
+ );
+
+ $psql->query_safe(qq(SELECT inj_io_error_flush_buffer_detach()));
+
$psql->quit();
}
diff --git a/src/test/modules/test_aio/test_aio--1.0.sql b/src/test/modules/test_aio/test_aio--1.0.sql
index cb168e2e08f..51af9a74b13 100644
--- a/src/test/modules/test_aio/test_aio--1.0.sql
+++ b/src/test/modules/test_aio/test_aio--1.0.sql
@@ -41,7 +41,8 @@ CREATE FUNCTION debug_print_rel_block(rel regclass, blockno int)
RETURNS pg_catalog.text STRICT
AS 'MODULE_PATHNAME' LANGUAGE C;
-CREATE FUNCTION invalidate_rel_block(rel regclass, blockno int)
+CREATE FUNCTION invalidate_rel_block(rel regclass, blockno int,
+ force_flush bool DEFAULT false)
RETURNS pg_catalog.void STRICT
AS 'MODULE_PATHNAME' LANGUAGE C;
@@ -132,3 +133,11 @@ AS 'MODULE_PATHNAME' LANGUAGE C;
CREATE FUNCTION inj_io_reopen_detach()
RETURNS pg_catalog.void STRICT
AS 'MODULE_PATHNAME' LANGUAGE C;
+
+CREATE FUNCTION inj_io_error_flush_buffer_attach()
+RETURNS pg_catalog.void STRICT
+AS 'MODULE_PATHNAME' LANGUAGE C;
+
+CREATE FUNCTION inj_io_error_flush_buffer_detach()
+RETURNS pg_catalog.void STRICT
+AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c
index a89cbd5786d..297800107a6 100644
--- a/src/test/modules/test_aio/test_aio.c
+++ b/src/test/modules/test_aio/test_aio.c
@@ -50,6 +50,7 @@ typedef struct InjIoErrorState
bool enabled_short_read;
bool enabled_reopen;
+ bool enabled_error_flush_buffer;
bool enabled_completion_wait;
Oid completion_wait_relfilenode;
@@ -131,6 +132,12 @@ test_aio_shmem_startup(void)
0);
InjectionPointLoad("aio-worker-after-reopen");
+ InjectionPointAttach("flush-buffer-after-smgr-write",
+ "test_aio",
+ "inj_io_error_flush_buffer",
+ NULL,
+ 0);
+ InjectionPointLoad("flush-buffer-after-smgrwrite");
#endif
}
else
@@ -142,6 +149,7 @@ test_aio_shmem_startup(void)
#ifdef USE_INJECTION_POINTS
InjectionPointLoad("aio-process-completion-before-shared");
InjectionPointLoad("aio-worker-after-reopen");
+ InjectionPointLoad("flush-buffer-after-smgr-write");
elog(LOG, "injection point loaded");
#endif
}
@@ -489,7 +497,7 @@ read_rel_block_ll(PG_FUNCTION_ARGS)
/* helper for invalidate_rel_block() and evict_rel() */
static void
-invalidate_one_block(Relation rel, ForkNumber forknum, BlockNumber blkno)
+invalidate_one_block(Relation rel, ForkNumber forknum, BlockNumber blkno, bool force_flush)
{
PrefetchBufferResult pr;
Buffer buf;
@@ -513,6 +521,9 @@ invalidate_one_block(Relation rel, ForkNumber forknum, BlockNumber blkno)
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
+ if (force_flush)
+ MarkBufferDirty(buf);
+
if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY)
{
if (BufferIsLocal(buf))
@@ -537,11 +548,12 @@ invalidate_rel_block(PG_FUNCTION_ARGS)
{
Oid relid = PG_GETARG_OID(0);
BlockNumber blkno = PG_GETARG_UINT32(1);
+ bool force_flush = PG_GETARG_BOOL(2);
Relation rel;
rel = relation_open(relid, AccessExclusiveLock);
- invalidate_one_block(rel, MAIN_FORKNUM, blkno);
+ invalidate_one_block(rel, MAIN_FORKNUM, blkno, force_flush);
relation_close(rel, AccessExclusiveLock);
@@ -577,7 +589,7 @@ evict_rel(PG_FUNCTION_ARGS)
for (int blkno = 0; blkno < nblocks; blkno++)
{
- invalidate_one_block(rel, forknum, blkno);
+ invalidate_one_block(rel, forknum, blkno, false);
}
}
}
@@ -1035,6 +1047,9 @@ extern PGDLLEXPORT void inj_io_completion_hook(const char *name,
extern PGDLLEXPORT void inj_io_reopen(const char *name,
const void *private_data,
void *arg);
+extern PGDLLEXPORT void inj_io_error_flush_buffer(const char *name,
+ const void *private_data,
+ void *arg);
static bool
inj_io_short_read_matches(PgAioHandle *ioh)
@@ -1203,6 +1218,18 @@ inj_io_reopen(const char *name, const void *private_data, void *arg)
if (inj_io_error_state->enabled_reopen)
elog(ERROR, "injection point triggering failure to reopen ");
}
+
+void
+inj_io_error_flush_buffer(const char *name, const void *private_data, void *arg)
+{
+ ereport(LOG,
+ errmsg("error_flush_buffer injection point called, is enabled: %d",
+ inj_io_error_state->enabled_error_flush_buffer),
+ errhidestmt(true), errhidecontext(true));
+
+ if (inj_io_error_state->enabled_error_flush_buffer)
+ elog(ERROR, "injection point triggering failure to flush buffer ");
+}
#endif
PG_FUNCTION_INFO_V1(inj_io_completion_wait);
@@ -1297,3 +1324,28 @@ inj_io_reopen_detach(PG_FUNCTION_ARGS)
#endif
PG_RETURN_VOID();
}
+
+PG_FUNCTION_INFO_V1(inj_io_error_flush_buffer_attach);
+Datum
+inj_io_error_flush_buffer_attach(PG_FUNCTION_ARGS)
+{
+#ifdef USE_INJECTION_POINTS
+ inj_io_error_state->enabled_error_flush_buffer = true;
+#else
+ elog(ERROR, "injection points not supported");
+#endif
+
+ PG_RETURN_VOID();
+}
+
+PG_FUNCTION_INFO_V1(inj_io_error_flush_buffer_detach);
+Datum
+inj_io_error_flush_buffer_detach(PG_FUNCTION_ARGS)
+{
+#ifdef USE_INJECTION_POINTS
+ inj_io_error_state->enabled_error_flush_buffer = false;
+#else
+ elog(ERROR, "injection points not supported");
+#endif
+ PG_RETURN_VOID();
+}
--
2.51.0
From 58828b0230e7cd668f65039c56a3bc11e52aeffd Mon Sep 17 00:00:00 2001
From: Yura Sokolov <[email protected]>
Date: Fri, 27 Mar 2026 21:19:41 +0300
Subject: [PATCH v2 3/3] bufmgr: print flag names in DebugPrintBufferRefcount
---
src/backend/storage/buffer/bufmgr.c | 42 +++++++++++++++++++++-----
src/test/modules/test_aio/t/001_aio.pl | 6 ++--
2 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index fd12566e674..5e9820ccc78 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -48,6 +48,7 @@
#include "common/hashfn.h"
#include "executor/instrument.h"
#include "lib/binaryheap.h"
+#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
@@ -4371,9 +4372,10 @@ DebugPrintBufferRefcount(Buffer buffer)
{
BufferDesc *buf;
int32 loccount;
- char *result;
ProcNumber backend;
uint64 buf_state;
+ StringInfoData str;
+ char flag_prefix = '=';
Assert(BufferIsValid(buffer));
if (BufferIsLocal(buffer))
@@ -4389,16 +4391,39 @@ DebugPrintBufferRefcount(Buffer buffer)
backend = INVALID_PROC_NUMBER;
}
+ initStringInfoExt(&str, 256);
+
/* theoretically we should lock the bufHdr here */
buf_state = pg_atomic_read_u64(&buf->state);
- result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)",
- buffer,
- relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend,
- BufTagGetForkNum(&buf->tag)).str,
- buf->tag.blockNum, buf_state & BUF_FLAG_MASK,
- BUF_STATE_GET_REFCOUNT(buf_state), loccount);
- return result;
+ appendStringInfo(&str, "[%03d] (rel=%s, blockNum=%u, flags",
+ buffer,
+ relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend,
+ BufTagGetForkNum(&buf->tag)).str,
+ buf->tag.blockNum);
+#define appendFlag(flag) do { \
+ if (buf_state & flag) { \
+ appendStringInfoChar(&str, flag_prefix); \
+ appendStringInfoString(&str, #flag); \
+ flag_prefix = '|'; \
+ } \
+} while(0)
+ appendFlag(BM_LOCKED);
+ appendFlag(BM_DIRTY);
+ appendFlag(BM_VALID);
+ appendFlag(BM_TAG_VALID);
+ appendFlag(BM_IO_IN_PROGRESS);
+ appendFlag(BM_IO_ERROR);
+ appendFlag(BM_PIN_COUNT_WAITER);
+ appendFlag(BM_CHECKPOINT_NEEDED);
+ appendFlag(BM_PERMANENT);
+ appendFlag(BM_LOCK_HAS_WAITERS);
+ appendFlag(BM_LOCK_WAKE_IN_PROGRESS);
+#undef appendFlag
+
+ appendStringInfo(&str, ", refcount=%u %d)",
+ BUF_STATE_GET_REFCOUNT(buf_state), loccount);
+ return str.data;
}
/*
@@ -4562,6 +4587,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object,
false);
INJECTION_POINT("flush-buffer-after-smgr-write", buf);
+
/*
* When a strategy is in use, only flushes of dirty buffers already in the
* strategy ring are counted as strategy writes (IOCONTEXT
diff --git a/src/test/modules/test_aio/t/001_aio.pl b/src/test/modules/test_aio/t/001_aio.pl
index 54061e0425b..35d42cfdfca 100644
--- a/src/test/modules/test_aio/t/001_aio.pl
+++ b/src/test/modules/test_aio/t/001_aio.pl
@@ -344,8 +344,7 @@ SELECT modify_rel_block('tmp_corr', 1, corrupt_header=>true);
$tblname eq 'tbl_corr'
? qr/invalid page in block 1 of relation "base\/\d+\/\d+/
: qr/invalid page in block 1 of relation "base\/\d+\/t\d+_\d+/;
- # BM_IO_ERROR and BM_TAG_VALID should be set
- my $debug_print_re = qr/blockNum=1, flags=0x.?a000000, refcount=0/;
+ my $debug_print_re = qr/blockNum=1, flags=BM_TAG_VALID\|BM_IO_ERROR\S*, refcount=0/;
# verify the error is reported in custom C code
psql_like(
@@ -828,12 +827,11 @@ SELECT invalidate_rel_block('tbl_ok', 2);
qr/^$/,
qr/ERROR:.*injection point triggering failure to flush buffer/
);
- # BM_IO_ERROR, BM_VALID and BM_TAG_VALID should be set
psql_like(
$io_method, $psql,
"validate flags of 'tbl_ok' page after read_rel_block_ll()",
qq(SELECT debug_print_rel_block('tbl_ok', 2)),
- qr/blockNum=2, flags=0x.?b.00000, refcount=0/, qr/^$/);
+ qr/blockNum=2, flags=BM_DIRTY\|BM_VALID\|BM_TAG_VALID\|BM_IO_ERROR\S*, refcount=0/, qr/^$/);
# Validate second attempt leads to "Multiple failures" message
psql_like(
$io_method, $psql,
--
2.51.0