From bc41ea1629f9e16f1c92c3475befecb0f6ef9a8c Mon Sep 17 00:00:00 2001 From: "iwata.aya" Date: Thu, 25 Dec 2025 17:16:55 +0900 Subject: [PATCH v0011 2/2] Renamed the flag to BGWORKER_PROTECTED and set default behavior to Terminate. --- doc/src/sgml/bgworker.sgml | 6 +- src/backend/postmaster/bgworker.c | 2 +- src/backend/storage/ipc/procarray.c | 2 +- src/include/postmaster/bgworker.h | 2 +- .../worker_spi/t/002_worker_terminate.pl | 117 ++++++++++++------ src/test/modules/worker_spi/worker_spi.c | 6 +- 6 files changed, 90 insertions(+), 45 deletions(-) diff --git a/doc/src/sgml/bgworker.sgml b/doc/src/sgml/bgworker.sgml index a7c238750fc..f56a1850ffb 100644 --- a/doc/src/sgml/bgworker.sgml +++ b/doc/src/sgml/bgworker.sgml @@ -109,11 +109,11 @@ typedef struct BackgroundWorker - BGWORKER_INTERRUPTABLE + BGWORKER_PROTECTED - BGWORKER_INTERRUPTABLE - Requests termination of the background worker when its connected database is + BGWORKER_PROTECTED + Prevents termination of the background worker when its connected database is dropped, renamed, moved to a different tablespace, or used as a template for CREATE DATABASE. Specifically, the postmaster sends a termination signal when any of these commands affect the worker's database: diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 8334b75548c..4e0aa195140 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -1421,7 +1421,7 @@ TerminateInterruptableBgWorkersByDbOid(Oid databaseId) BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno]; if (slot->in_use && - (slot->worker.bgw_flags & BGWORKER_INTERRUPTABLE)) + !(slot->worker.bgw_flags & BGWORKER_PROTECTED)) { PGPROC *proc = BackendPidGetProc(slot->pid); diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index de80422caea..68b6aff151f 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -3780,7 +3780,7 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared) /* * Terminate all background workers for this database, if they had - * requested it (BGWORKER_INTERRUPTABLE) + * requested it (BGWORKER_PROTECTED) */ TerminateInterruptableBgWorkersByDbOid(databaseId); diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h index e43881448d5..022b8130a64 100644 --- a/src/include/postmaster/bgworker.h +++ b/src/include/postmaster/bgworker.h @@ -64,7 +64,7 @@ * database command. * Requires BGWORKER_SHMEM_ACCESS and BGWORKER_BACKEND_DATABASE_CONNECTION. */ -#define BGWORKER_INTERRUPTABLE 0x0004 +#define BGWORKER_PROTECTED 0x0004 /* * This class is used internally for parallel queries, to keep track of the diff --git a/src/test/modules/worker_spi/t/002_worker_terminate.pl b/src/test/modules/worker_spi/t/002_worker_terminate.pl index 5467e423fd9..ca59f3a836b 100644 --- a/src/test/modules/worker_spi/t/002_worker_terminate.pl +++ b/src/test/modules/worker_spi/t/002_worker_terminate.pl @@ -50,6 +50,21 @@ sub run_db_command note("background worker can be terminated at $testname"); } +# Confirm a background worker is still running +sub confirm_bgworker_running +{ + my ($node, $dbname, $testinfo) = @_; + + my $result = $node->safe_psql( + "$dbname", qq( + SELECT count(1) FROM pg_stat_activity + WHERE backend_type = 'worker_spi dynamic';)); + + is($result, '1', + "background worker is not stopped after $testinfo"); + +} + my $node = PostgreSQL::Test::Cluster->new('mynode'); $node->init; $node->start; @@ -64,10 +79,15 @@ if (!$node->check_extension('injection_points')) $node->safe_psql('postgres', 'CREATE EXTENSION worker_spi;'); -# Launch a background worker without BGWORKER_INTERRUPTABLE +# Launch a background worker without BGWORKER_PROTECTED launch_bgworker($node, 'postgres', 0, "false"); -# Ensure CREATE DATABASE WITH TEMPLATE fails because background worker retains +# Ensure CREATE DATABASE WITH TEMPLATE sucseeds because background worker retains + +run_db_command( + $node, + "CREATE DATABASE testdb WITH TEMPLATE postgres", + "CREATE DATABASE WITH TEMPLATE"); # The injection point 'reduce-ncounts' reduces the number of backend # retries, allowing for shorter test runs. See CountOtherDBBackends(). @@ -77,22 +97,20 @@ $node->safe_psql('postgres', my $stderr; +# Ensure BGWORKER_PROTECTED allows background workers not to be +# terminated at some database manipulations. +# +# Testcase 1: CREATE DATABASE WITH TEMPLATE +launch_bgworker($node, 'postgres', 1, "true"); $node->psql( 'postgres', - "CREATE DATABASE testdb WITH TEMPLATE postgres", + "CREATE DATABASE testdb2 WITH TEMPLATE postgres", stderr => \$stderr); ok( $stderr =~ - "source database \"postgres\" is being accessed by other users", + "source database \"postgres\" is being accessed by other users", "background worker blocked the database creation"); -# Confirm a background worker is still running -my $result = $node->safe_psql( - "postgres", qq( - SELECT count(1) FROM pg_stat_activity - WHERE backend_type = 'worker_spi dynamic';)); - -is($result, '1', - "background worker is still running after CREATE DATABASE WITH TEMPLATE"); +confirm_bgworker_running($node, "postgres", "CREATE DATABASE WITH TEMPLATE"); # Terminate the worker for upcoming tests $node->safe_psql( @@ -100,26 +118,23 @@ $node->safe_psql( SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE backend_type = 'worker_spi dynamic';)); -# The injection point won't be used anymore, release it. -$node->safe_psql('postgres', - "SELECT injection_points_detach('reduce-ncounts');"); - -# Ensure BGWORKER_INTERRUPTABLE allows background workers to be -# terminated at some database manipulations. -# -# Testcase 1: CREATE DATABASE WITH TEMPLATE -launch_bgworker($node, 'postgres', 1, "true"); -run_db_command( - $node, - "CREATE DATABASE testdb WITH TEMPLATE postgres", - "CREATE DATABASE WITH TEMPLATE"); - # Testcase 2: ALTER DATABASE RENAME launch_bgworker($node, 'testdb', 2, "true"); -run_db_command( - $node, +$node->psql( + 'testdb', "ALTER DATABASE testdb RENAME TO renameddb", - "ALTER DATABASE RENAME"); + stderr => \$stderr); +ok( $stderr =~ + "current database cannot be renamed", + "background worker blocked the alter database rename to"); + +confirm_bgworker_running($node, "testdb", "ALTER DATABASE RENAME TO"); + +# Terminate the worker for upcoming tests +$node->safe_psql( + "testdb", qq( + SELECT pg_terminate_backend(pid) + FROM pg_stat_activity WHERE backend_type = 'worker_spi dynamic';)); # Preparation for the next test; create another tablespace my $tablespace = PostgreSQL::Test::Utils::tempdir; @@ -127,14 +142,44 @@ $node->safe_psql('postgres', "CREATE TABLESPACE test_tablespace LOCATION '$tablespace'"); # Testcase 3: ALTER DATABASE SET TABLESPACE -launch_bgworker($node, 'renameddb', 3, "true"); -run_db_command( - $node, - "ALTER DATABASE renameddb SET TABLESPACE test_tablespace", - "ALTER DATABASE SET TABLESPACE"); +launch_bgworker($node, 'testdb', 3, "true"); +$node->psql( + 'testdb', + "ALTER DATABASE testdb SET TABLESPACE test_tablespace", + stderr => \$stderr); +ok( $stderr =~ + "cannot change the tablespace of the currently open database", + "background worker blocked the alter database set tablespace"); + +confirm_bgworker_running($node, "testdb", "ALTER DATABASE SET TABLESPACE"); + +# Terminate the worker for upcoming tests +$node->safe_psql( + "testdb", qq( + SELECT pg_terminate_backend(pid) + FROM pg_stat_activity WHERE backend_type = 'worker_spi dynamic';)); # Testcase 4: DROP DATABASE -launch_bgworker($node, 'renameddb', 4, "true"); -run_db_command($node, "DROP DATABASE renameddb", "DROP DATABASE"); +launch_bgworker($node, 'testdb', 4, "true"); +$node->psql( + 'testdb', + "DROP DATABASE testdb", + stderr => \$stderr); +ok( $stderr =~ + "cannot drop the currently open database", + "background worker blocked the database drop"); + +confirm_bgworker_running($node, "testdb", "DROP DATABASE"); + +# Terminate the worker +$node->safe_psql( + "testdb", qq( + SELECT pg_terminate_backend(pid) + FROM pg_stat_activity WHERE backend_type = 'worker_spi dynamic';)); + + +# The injection point won't be used anymore, release it. +$node->safe_psql('postgres', + "SELECT injection_points_detach('reduce-ncounts');"); done_testing(); diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c index 50d16aaf9a8..04ef060ff42 100644 --- a/src/test/modules/worker_spi/worker_spi.c +++ b/src/test/modules/worker_spi/worker_spi.c @@ -404,14 +404,14 @@ worker_spi_launch(PG_FUNCTION_ARGS) Size ndim; int nelems; Datum *datum_flags; - bool request_termination = PG_GETARG_BOOL(4); + bool prevent_termination = PG_GETARG_BOOL(4); memset(&worker, 0, sizeof(worker)); worker.bgw_flags = BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION; - if (request_termination) - worker.bgw_flags |= BGWORKER_INTERRUPTABLE; + if (prevent_termination) + worker.bgw_flags |= BGWORKER_PROTECTED; worker.bgw_start_time = BgWorkerStart_RecoveryFinished; worker.bgw_restart_time = BGW_NEVER_RESTART; -- 2.39.3