v0011-0002-Renamed-the-flag-to-BGWORKER_PROTECTED.patch

application/octet-stream

Filename: v0011-0002-Renamed-the-flag-to-BGWORKER_PROTECTED.patch
Type: application/octet-stream
Part: 1
Message: RE: [PROPOSAL] Termination of Background Workers for ALTER/DROP DATABASE
From bc41ea1629f9e16f1c92c3475befecb0f6ef9a8c Mon Sep 17 00:00:00 2001
From: "iwata.aya" <iwata.aya@fujitsu.com>
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
     </varlistentry>
 
     <varlistentry>
-     <term><literal>BGWORKER_INTERRUPTABLE</literal></term>
+     <term><literal>BGWORKER_PROTECTED</literal></term>
      <listitem>
      <para>
-      <indexterm><primary>BGWORKER_INTERRUPTABLE</primary></indexterm>
-      Requests termination of the background worker when its connected database is
+      <indexterm><primary>BGWORKER_PROTECTED</primary></indexterm>
+      Prevents termination of the background worker when its connected database is
       dropped, renamed, moved to a different tablespace, or used as a template for
       <command>CREATE DATABASE</command>. 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