From 8f1d6d9c276e0d7810a02309ee14d589d6bad14a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 21:43:18 +0000 Subject: [PATCH] Return B_SYSTEM_BG_WORKER slots to the bgworker pool on release System background workers (BGWORKER_CLASS_SYSTEM, used by orioledb's S3 workers) get their postmaster child slot from the B_BG_WORKER pool in do_start_bgworker() and are then retyped to B_SYSTEM_BG_WORKER so the shutdown state machine lets them keep running. On exit, however, ReleasePostmasterChildSlot() returned the slot to the pool of the current backend type: the separate size-1 B_SYSTEM_BG_WORKER pool that nothing ever allocates from. The slot number is from the B_BG_WORKER range, so the pool range sanity check failed and the postmaster itself exited with 'pmchild freelist for backend type 6 is corrupt' - any S3 worker exit (a clean SIGTERM, or the FATAL that any S3 request error raises) took down the entire cluster. Remap B_SYSTEM_BG_WORKER to the B_BG_WORKER pool on release, exactly like the B_WAL_SENDER -> B_BACKEND remap above it, and drop the unused (and mis-sized: there can be s3_num_workers of these) size-1 pool. B_WAL_SENDER analogously has no pool of its own, and AssignPostmasterChildSlot() reports an error for zero-size pools if anything ever tries to allocate from it directly. Reproduced by test/t/s3_transient_error_test.py (orioledb repo): one injected 500 on one S3 PUT kills the whole cluster on PG18 builds, while PG17 builds (no pmchild.c, no B_SYSTEM_BG_WORKER) survive the same event with a worker restart. Co-Authored-By: Claude Fable 5 --- src/backend/postmaster/pmchild.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/backend/postmaster/pmchild.c b/src/backend/postmaster/pmchild.c index b2720d76862..cb1cd064569 100644 --- a/src/backend/postmaster/pmchild.c +++ b/src/backend/postmaster/pmchild.c @@ -107,7 +107,6 @@ InitPostmasterChildSlots(void) * There can be only one of each of these running at a time. They each * get their own pool of just one entry. */ - pmchild_pools[B_SYSTEM_BG_WORKER].size = 1; pmchild_pools[B_AUTOVAC_LAUNCHER].size = 1; pmchild_pools[B_SLOTSYNC_WORKER].size = 1; pmchild_pools[B_ARCHIVER].size = 1; @@ -252,6 +251,14 @@ ReleasePostmasterChildSlot(PMChild *pmchild) /* WAL senders start out as regular backends, and share the pool */ if (pmchild->bkend_type == B_WAL_SENDER) pool = &pmchild_pools[B_BACKEND]; + + /* + * System background workers are allocated from the regular bgworker + * pool and retyped in do_start_bgworker(), so their slots must be + * returned to that pool. + */ + else if (pmchild->bkend_type == B_SYSTEM_BG_WORKER) + pool = &pmchild_pools[B_BG_WORKER]; else pool = &pmchild_pools[pmchild->bkend_type];