From 81f67744ed2b191e1613f2fd8b2ab5a271639429 Mon Sep 17 00:00:00 2001 From: "iwata.aya" Date: Thu, 11 Sep 2025 21:16:51 +0900 Subject: [PATCH v0001] Allow background workers to be terminated at DROP DATABASE --- doc/src/sgml/bgworker.sgml | 12 ++++ src/backend/postmaster/bgworker.c | 88 +++++++++++++++++++++++++++++ src/backend/storage/ipc/procarray.c | 6 ++ src/include/postmaster/bgworker.h | 13 +++++ 4 files changed, 119 insertions(+) diff --git a/doc/src/sgml/bgworker.sgml b/doc/src/sgml/bgworker.sgml index 2c393385a91..cef2ef53c15 100644 --- a/doc/src/sgml/bgworker.sgml +++ b/doc/src/sgml/bgworker.sgml @@ -283,6 +283,18 @@ typedef struct BackgroundWorker BGWH_POSTMASTER_DIED. + + By using AcceptBackgroundWorkerCancel(oid, + int) with the database's OID and a flag + value indicating whether to cancel, the DBMS daemon can issue a termination + signal to the background worker when changes occur in the database it is + connected to, thereby terminating the target background worker. This occurs + only when significant changes affecting the entire database take place. + Specifically, major changes include when the DROP DATABASE, + ALTER DATABASE RENAME TO, and + ALTER DATABASE SET TABLESPACE commands are executed. + + Background workers can send asynchronous notification messages, either by using the NOTIFY command via SPI, diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 1ad65c237c3..bcdd931af06 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -356,6 +356,22 @@ BackgroundWorkerStateChange(bool allow_new_workers) return; } + /* + * Set shmem slot number, and initialize cancel flags. + */ + rw->rw_worker.bgw_shmem_slot = slotno; + + rw->rw_worker.bgw_cancel_databaseId = InvalidOid; + rw->rw_worker.bgw_cancel_flags = BGWORKER_CANCEL_NOACCEPT; + + /* + * Update the contents in the shared memory also, these are used in + * EXEC_BACKEND (win32) case + */ + slot->worker.bgw_shmem_slot = slotno; + slot->worker.bgw_cancel_databaseId = InvalidOid; + slot->worker.bgw_cancel_flags = BGWORKER_CANCEL_NOACCEPT; + /* * Copy strings in a paranoid way. If shared memory is corrupted, the * source data might not even be NUL-terminated. @@ -1396,3 +1412,75 @@ GetBackgroundWorkerTypeByPid(pid_t pid) return result; } + +/* + * Accept background worker cancel. + * Set cancel flags and databaseId. + */ +void +AcceptBackgroundWorkerCancel(Oid databaseId, int cancel_flags) +{ + int slotno; + BackgroundWorkerSlot *slot; + + /* Get shmem slot number from BGW entry. */ + Assert(MyBgworkerEntry); + slotno = MyBgworkerEntry->bgw_shmem_slot; + + /* Get shmem slot address. */ + Assert(slotno < BackgroundWorkerData->total_slots); + slot = &BackgroundWorkerData->slot[slotno]; + + /* Set cancel flags and databaseId to sgmem slot. */ + /* 1st, set databaseId. */ + slot->worker.bgw_cancel_databaseId = databaseId; + /* 2nd, set cancel flags. */ + slot->worker.bgw_cancel_flags = cancel_flags; + + /* + * This operation doesn't need LOCK, because 'bgw_cancel_flags' is 32bit + * value. + */ +} + +/* + * Cancel background workers. + */ +void +CancelBackgroundWorkers(Oid databaseId, int cancel_flags) +{ + int slotno; + bool signal_postmaster = false; + + LWLockAcquire(BackgroundWorkerLock, LW_EXCLUSIVE); + + for (slotno = 0; slotno < BackgroundWorkerData->total_slots; ++slotno) + { + BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno]; + + /* Check worker slot. */ + if (slot->in_use) + { + /* 1st, check cancel flags. */ + if (slot->worker.bgw_cancel_flags & cancel_flags) + { + /* 2nd, compare databaseId. */ + if (slot->worker.bgw_cancel_databaseId == databaseId) + { + /* + * Set terminate flag in shared memory, unless slot has + * been reused. + */ + slot->terminate = true; + signal_postmaster = true; + } + } + } + } + + LWLockRelease(BackgroundWorkerLock); + + /* Make sure the postmaster notices the change to shared memory. */ + if (signal_postmaster) + SendPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE); +} diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 200f72c6e25..36571354324 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -56,6 +56,7 @@ #include "catalog/pg_authid.h" #include "miscadmin.h" #include "pgstat.h" +#include "postmaster/bgworker.h" #include "port/pg_lfind.h" #include "storage/proc.h" #include "storage/procarray.h" @@ -3768,6 +3769,11 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared) for (index = 0; index < nautovacs; index++) (void) kill(autovac_pids[index], SIGTERM); /* ignore any error */ + /* + * Cancel background workers by admin commands. + */ + CancelBackgroundWorkers(databaseId, BGWORKER_CANCEL_ADMIN_COMMANDS); + /* sleep, then try again */ pg_usleep(100 * 1000L); /* 100ms */ } diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h index 058667a47a0..8cf49f5810b 100644 --- a/src/include/postmaster/bgworker.h +++ b/src/include/postmaster/bgworker.h @@ -66,8 +66,14 @@ * background workers should not use this class. */ #define BGWORKER_CLASS_PARALLEL 0x0010 + /* add additional bgworker classes here */ +/* + * Flags for cancel by admin commands. + */ +#define BGWORKER_CANCEL_NOACCEPT 0x0000 +#define BGWORKER_CANCEL_ADMIN_COMMANDS 0x0001 typedef void (*bgworker_main_type) (Datum main_arg); @@ -98,6 +104,9 @@ typedef struct BackgroundWorker Datum bgw_main_arg; char bgw_extra[BGW_EXTRALEN]; pid_t bgw_notify_pid; /* SIGUSR1 this backend on start/stop */ + int bgw_shmem_slot; /* shmem slot ID */ + Oid bgw_cancel_databaseId; /* cancel target */ + int bgw_cancel_flags; /* cancel by admin commands */ } BackgroundWorker; typedef enum BgwHandleStatus @@ -161,4 +170,8 @@ extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, ui extern void BackgroundWorkerBlockSignals(void); extern void BackgroundWorkerUnblockSignals(void); +/* Cancel background workers. */ +extern void AcceptBackgroundWorkerCancel(Oid databaseId, int cancel_flags); +extern void CancelBackgroundWorkers(Oid databaseId, int cancel_flags); + #endif /* BGWORKER_H */ -- 2.39.3