From: Noah Misch <noah@leadboat.com>
Date: Fri, 27 Sep 2024 22:28:56 +0000 (-0700)
Subject: Avoid 037_invalid_database.pl hang under debug_discard_caches.
X-Git-Tag: REL_14_14~61
X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=0c827fbdb81ad873921c3fae4d973151d8a00785;p=postgresql.git

Avoid 037_invalid_database.pl hang under debug_discard_caches.

Back-patch to v12 (all supported versions).
---

diff --git a/src/test/recovery/t/037_invalid_database.pl b/src/test/recovery/t/037_invalid_database.pl
index 29b9bb6977c..7e5e0bb31f9 100644
--- a/src/test/recovery/t/037_invalid_database.pl
+++ b/src/test/recovery/t/037_invalid_database.pl
@@ -84,7 +84,10 @@ is($node->psql('postgres', 'DROP DATABASE regression_invalid'),
 # Test that interruption of DROP DATABASE is handled properly. To ensure the
 # interruption happens at the appropriate moment, we lock pg_tablespace. DROP
 # DATABASE scans pg_tablespace once it has reached the "irreversible" part of
-# dropping the database, making it a suitable point to wait.
+# dropping the database, making it a suitable point to wait.  Since relcache
+# init reads pg_tablespace, establish each connection before locking.  This
+# avoids a connection-time hang with debug_discard_caches.
+my $cancel = $node->background_psql('postgres', on_error_stop => 1);
 my $bgpsql = $node->background_psql('postgres', on_error_stop => 0);
 my $pid = $bgpsql->query('SELECT pg_backend_pid()');
 
@@ -100,14 +103,19 @@ ok( $bgpsql->query_safe(
 # Try to drop. This will wait due to the still held lock.
 $bgpsql->query_until(qr//, "DROP DATABASE regression_invalid_interrupt;\n");
 
-# Ensure we're waiting for the lock
-$node->poll_query_until('postgres',
-	qq(SELECT EXISTS(SELECT * FROM pg_locks WHERE NOT granted AND relation = 'pg_tablespace'::regclass AND mode = 'AccessShareLock');)
-);
 
-# and finally interrupt the DROP DATABASE
-ok($node->safe_psql('postgres', "SELECT pg_cancel_backend($pid)"),
+# Once the DROP DATABASE is waiting for the lock, interrupt it.
+ok( $cancel->query_safe(
+		qq(
+	DO \$\$
+	BEGIN
+		WHILE NOT EXISTS(SELECT * FROM pg_locks WHERE NOT granted AND relation = 'pg_tablespace'::regclass AND mode = 'AccessShareLock') LOOP
+			PERFORM pg_sleep(.1);
+		END LOOP;
+	END\$\$;
+	SELECT pg_cancel_backend($pid);)),
 	"canceling DROP DATABASE");
+$cancel->quit();
 
 # wait for cancellation to be processed
 ok( pump_until(
@@ -116,7 +124,8 @@ ok( pump_until(
 	"cancel processed");
 $bgpsql->{stderr} = '';
 
-# verify that connection to the database aren't allowed
+# Verify that connections to the database aren't allowed.  The backend checks
+# this before relcache init, so the lock won't interfere.
 is($node->psql('regression_invalid_interrupt', ''),
 	2, "can't connect to invalid_interrupt database");