0001-DROP-TABLE-race-in-expand_vacuum_rel-skip-lock-path.patch.nocfbot

application/octet-stream

Filename: 0001-DROP-TABLE-race-in-expand_vacuum_rel-skip-lock-path.patch.nocfbot
Type: application/octet-stream
Part: 0
Message: Re: Track skipped tables during autovacuum and autoanalyze
From 3c3870959772869ceedc4445c5f88ff54f01b8ab Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <parragizs@gmail.com>
Date: Thu, 14 May 2026 21:16:24 +0000
Subject: [PATCH] DROP TABLE race in expand_vacuum_rel skip-lock path

---
 src/backend/commands/vacuum.c                 |  1 +
 src/test/recovery/meson.build                 |  1 +
 .../t/053_vacuum_skip_locked_drop_race.pl     | 54 +++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 src/test/recovery/t/053_vacuum_skip_locked_drop_race.pl

diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 51c5fc2fdaf..0edb56e67c9 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -961,6 +961,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 						 errmsg("skipping analyze of \"%s\" --- lock not available",
 								vrel->relation->relname)));
 
+			INJECTION_POINT("expand-vacuum-rel-skip-locked", NULL);
 			/* Get relid for statistics reporting */
 			relid = RangeVarGetRelid(vrel->relation, NoLock, true);
 
diff --git a/src/test/recovery/meson.build b/src/test/recovery/meson.build
index 36d789720a3..05190b26931 100644
--- a/src/test/recovery/meson.build
+++ b/src/test/recovery/meson.build
@@ -61,6 +61,7 @@ tests += {
       't/050_redo_segment_missing.pl',
       't/051_effective_wal_level.pl',
       't/052_checkpoint_segment_missing.pl',
+      't/053_vacuum_skip_locked_drop_race.pl',
     ],
   },
 }
diff --git a/src/test/recovery/t/053_vacuum_skip_locked_drop_race.pl b/src/test/recovery/t/053_vacuum_skip_locked_drop_race.pl
new file mode 100644
index 00000000000..417f6ec2541
--- /dev/null
+++ b/src/test/recovery/t/053_vacuum_skip_locked_drop_race.pl
@@ -0,0 +1,54 @@
+use strict;
+use warnings FATAL => 'all';
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('main');
+$node->init;
+$node->start;
+
+$node->safe_psql(
+	'postgres', q{
+	CREATE EXTENSION injection_points;
+	CREATE TABLE foo (id int);
+	SELECT injection_points_attach('expand-vacuum-rel-skip-locked', 'wait');
+});
+
+my $locker = $node->background_psql('postgres');
+$locker->query_safe(q{BEGIN; LOCK TABLE foo IN ACCESS EXCLUSIVE MODE;});
+
+my $log_offset = -s $node->logfile;
+
+my $vacuumer = $node->background_psql('postgres');
+$vacuumer->query_until(qr/start/,
+	qq(\\echo start\nVACUUM (SKIP_LOCKED) foo;\n));
+
+$node->wait_for_event('client backend', 'expand-vacuum-rel-skip-locked');
+
+ok( $node->log_contains(
+		qr/skipping vacuum of "foo" --- lock not available/,
+		$log_offset),
+	'VACUUM (SKIP_LOCKED) was skipped due to lock unavailability');
+
+$locker->query_safe(q{
+	COMMIT;
+	DROP TABLE foo;
+});
+$locker->quit;
+
+$node->safe_psql('postgres',
+	q{SELECT injection_points_wakeup('expand-vacuum-rel-skip-locked');});
+$vacuumer->quit;
+
+$node->safe_psql('postgres', q{SELECT pg_stat_force_next_flush();});
+
+my $total = $node->safe_psql('postgres', q{
+	SELECT coalesce(sum(skipped_vacuum_count), 0)
+	FROM pg_stat_all_tables;
+});
+chomp $total;
+
+cmp_ok($total, '>=', 1, 'skip event recorded in pg_stat_all_tables');
+
+done_testing();
-- 
2.54.0