On Wed, Sep 29, 2021 at 4:07 PM Thomas Munro <thomas.mu...@gmail.com> wrote: > Hmm, on closer inspection, isn't the lack of real interlocking with > checkpoints a bit suspect already? What stops bgwriter from writing > to the previous relfilenode generation's fd, if a relfilenode is > recycled while BgBufferSync() is running? Not sinval, and not the > above code that only runs between BgBufferSync() invocations.
I managed to produce a case where live data is written to an unlinked file and lost, with a couple of tweaks to get the right timing and simulate OID wraparound. See attached. If you run the following commands repeatedly with shared_buffers=256kB and bgwriter_lru_multiplier=10, you should see a number lower than 10,000 from the last query in some runs, depending on timing. create extension if not exists chaos; create extension if not exists pg_prewarm; drop table if exists t1, t2; checkpoint; vacuum pg_class; select clobber_next_oid(200000); create table t1 as select 42 i from generate_series(1, 10000); select pg_prewarm('t1'); -- fill buffer pool with t1 update t1 set i = i; -- dirty t1 buffers so bgwriter writes some select pg_sleep(2); -- give bgwriter some time drop table t1; checkpoint; vacuum pg_class; select clobber_next_oid(200000); create table t2 as select 0 i from generate_series(1, 10000); select pg_prewarm('t2'); -- fill buffer pool with t2 update t2 set i = 1 where i = 0; -- dirty t2 buffers so bgwriter writes some select pg_sleep(2); -- give bgwriter some time select pg_prewarm('pg_attribute'); -- evict all clean t2 buffers select sum(i) as t2_sum_should_be_10000 from t2; -- have any updates been lost?
From b116b80b2775b004e35a9e7be0a057ee2724041b Mon Sep 17 00:00:00 2001 From: Thomas Munro <thomas.mu...@gmail.com> Date: Thu, 30 Sep 2021 15:47:23 +1300 Subject: [PATCH 1/2] HACK: A function to control the OID allocator. --- src/test/modules/chaos/Makefile | 21 +++++++++++++++++++++ src/test/modules/chaos/chaos--1.0.sql | 8 ++++++++ src/test/modules/chaos/chaos.c | 26 ++++++++++++++++++++++++++ src/test/modules/chaos/chaos.control | 4 ++++ 4 files changed, 59 insertions(+) create mode 100644 src/test/modules/chaos/Makefile create mode 100644 src/test/modules/chaos/chaos--1.0.sql create mode 100644 src/test/modules/chaos/chaos.c create mode 100644 src/test/modules/chaos/chaos.control diff --git a/src/test/modules/chaos/Makefile b/src/test/modules/chaos/Makefile new file mode 100644 index 0000000000..ac69721af6 --- /dev/null +++ b/src/test/modules/chaos/Makefile @@ -0,0 +1,21 @@ +# src/test/modules/chaos/Makefile + +MODULE_big = chaos +OBJS = \ + $(WIN32RES) \ + chaos.o +PGFILEDESC = "chaos - module in which to write throwaway fault-injection hacks" + +EXTENSION = chaos +DATA = chaos--1.0.sql + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/chaos +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/chaos/chaos--1.0.sql b/src/test/modules/chaos/chaos--1.0.sql new file mode 100644 index 0000000000..5016f7e586 --- /dev/null +++ b/src/test/modules/chaos/chaos--1.0.sql @@ -0,0 +1,8 @@ +/* src/test/modules/chaos/chaos--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION chaos" to load this file. \quit + +CREATE FUNCTION clobber_next_oid(size BIGINT) + RETURNS pg_catalog.void STRICT + AS 'MODULE_PATHNAME' LANGUAGE C; diff --git a/src/test/modules/chaos/chaos.c b/src/test/modules/chaos/chaos.c new file mode 100644 index 0000000000..f1052f865e --- /dev/null +++ b/src/test/modules/chaos/chaos.c @@ -0,0 +1,26 @@ +#include "postgres.h" + +#include "access/transam.h" +#include "fmgr.h" +#include "storage/lwlock.h" + +#include <limits.h> + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(clobber_next_oid); + +Datum +clobber_next_oid(PG_FUNCTION_ARGS) +{ + int64 oid = PG_GETARG_INT64(0); + + if (oid < FirstNormalObjectId || oid > UINT_MAX) + elog(ERROR, "invalid oid"); + + LWLockAcquire(OidGenLock, LW_EXCLUSIVE); + ShmemVariableCache->nextOid = oid; + LWLockRelease(OidGenLock); + + PG_RETURN_VOID(); +} diff --git a/src/test/modules/chaos/chaos.control b/src/test/modules/chaos/chaos.control new file mode 100644 index 0000000000..137ab8a58d --- /dev/null +++ b/src/test/modules/chaos/chaos.control @@ -0,0 +1,4 @@ +comment = 'Test module for throwaway fault-injection hacks...' +default_version = '1.0' +module_pathname = '$libdir/chaos' +relocatable = true -- 2.30.2
From 2acc2ad31c1db268de0e8927d5c10ba2bb06e33c Mon Sep 17 00:00:00 2001 From: Thomas Munro <thomas.mu...@gmail.com> Date: Thu, 30 Sep 2021 17:16:01 +1300 Subject: [PATCH 2/2] HACK: Slow the bgwriter down a bit. --- src/backend/postmaster/bgwriter.c | 2 ++ src/backend/storage/buffer/bufmgr.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 5584f4bc24..b65284b1f6 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -238,7 +238,9 @@ BackgroundWriterMain(void) /* * Do one cycle of dirty-buffer writing. */ + elog(LOG, "=== begin BgBufferSync ==="); can_hibernate = BgBufferSync(&wb_context); + elog(LOG, "=== end BgBufferSync ==="); /* * Send off activity statistics to the stats collector diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index e88e4e918b..989125e37f 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -2452,6 +2452,8 @@ BgBufferSync(WritebackContext *wb_context) } else if (sync_state & BUF_REUSABLE) reusable_buffers++; + + pg_usleep(1000000); } PendingBgWriterStats.m_buf_written_clean += num_written; -- 2.30.2