v1-0001-pgstat_drop_relation-for-indexes.patch

text/plain

Filename: v1-0001-pgstat_drop_relation-for-indexes.patch
Type: text/plain
Part: 0
Message: pg_stat_have_stats() returns true for dropped indexes (or for index creation transaction rolled back)

Patch

Format: unified
Series: patch v1-0001
File+
src/backend/catalog/index.c 6 0
src/test/recovery/t/030_stats_cleanup_replica.pl 34 16
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index d7192f35e3..de10d2ade8 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1248,6 +1248,8 @@ index_create(Relation heapRelation,
 	}
 	else
 	{
+		/* ensure that stats are dropped if transaction aborts */
+		pgstat_create_relation(indexRelation);
 		index_build(heapRelation, indexRelation, indexInfo, false, true);
 	}
 
@@ -2325,6 +2327,9 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
 	if (RELKIND_HAS_STORAGE(userIndexRelation->rd_rel->relkind))
 		RelationDropStorage(userIndexRelation);
 
+	/* ensure that stats are dropped if transaction commits */
+	pgstat_drop_relation(userIndexRelation);
+
 	/*
 	 * Close and flush the index's relcache entry, to ensure relcache doesn't
 	 * try to rebuild it while we're deleting catalog entries. We keep the
@@ -2349,6 +2354,7 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
 	CatalogTupleDelete(indexRelation, &tuple->t_self);
 
 	ReleaseSysCache(tuple);
+
 	table_close(indexRelation, RowExclusiveLock);
 
 	/*
diff --git a/src/test/recovery/t/030_stats_cleanup_replica.pl b/src/test/recovery/t/030_stats_cleanup_replica.pl
index cc92ddbb52..04fe8a0997 100644
--- a/src/test/recovery/t/030_stats_cleanup_replica.pl
+++ b/src/test/recovery/t/030_stats_cleanup_replica.pl
@@ -29,11 +29,12 @@ $node_standby->start;
 
 my $sect = 'initial';
 
-my ($dboid, $tableoid, $funcoid) =
+my ($dboid, $tableoid, $indexoid, $funcoid) =
   populate_standby_stats('postgres', 'public');
 test_standby_func_tab_stats_status('postgres',
-	$dboid, $tableoid, $funcoid, 't');
+	$dboid, $tableoid, $indexoid, $funcoid, 't');
 
+drop_index_by_oid('postgres', $indexoid);
 drop_table_by_oid('postgres', $tableoid);
 drop_function_by_oid('postgres', $funcoid);
 
@@ -41,7 +42,7 @@ $sect = 'post drop';
 my $primary_lsn = $node_primary->lsn('flush');
 $node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
 test_standby_func_tab_stats_status('postgres',
-	$dboid, $tableoid, $funcoid, 'f');
+	$dboid, $tableoid, $indexoid, $funcoid, 'f');
 
 
 ## Test that stats are cleaned up on standby after dropping indirectly
@@ -52,11 +53,11 @@ $node_primary->safe_psql('postgres', "CREATE SCHEMA drop_schema_test1");
 $primary_lsn = $node_primary->lsn('flush');
 $node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
 
-($dboid, $tableoid, $funcoid) =
+($dboid, $tableoid, $indexoid, $funcoid) =
   populate_standby_stats('postgres', 'drop_schema_test1');
 
 test_standby_func_tab_stats_status('postgres',
-	$dboid, $tableoid, $funcoid, 't');
+	$dboid, $tableoid, $indexoid, $funcoid, 't');
 $node_primary->safe_psql('postgres', "DROP SCHEMA drop_schema_test1 CASCADE");
 
 $sect = "post schema drop";
@@ -66,7 +67,7 @@ $node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
 
 # verify table and function stats removed from standby
 test_standby_func_tab_stats_status('postgres',
-	$dboid, $tableoid, $funcoid, 'f');
+	$dboid, $tableoid, $indexoid, $funcoid, 'f');
 
 
 ## Test that stats are cleaned up on standby after dropping database
@@ -77,10 +78,10 @@ $node_primary->safe_psql('postgres', "CREATE DATABASE test");
 $primary_lsn = $node_primary->lsn('flush');
 $node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
 
-($dboid, $tableoid, $funcoid) = populate_standby_stats('test', 'public');
+($dboid, $tableoid, $indexoid, $funcoid) = populate_standby_stats('test', 'public');
 
 # verify stats are present
-test_standby_func_tab_stats_status('test', $dboid, $tableoid, $funcoid, 't');
+test_standby_func_tab_stats_status('test', $dboid, $tableoid, $indexoid, $funcoid, 't');
 test_standby_db_stats_status('test', $dboid, 't');
 
 $node_primary->safe_psql('postgres', "DROP DATABASE test");
@@ -92,7 +93,7 @@ $node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
 # Note that this connects to 'postgres' but provides the dboid of dropped db
 # 'test' which we acquired previously
 test_standby_func_tab_stats_status('postgres',
-	$dboid, $tableoid, $funcoid, 'f');
+	$dboid, $tableoid, $indexoid, $funcoid, 'f');
 
 test_standby_db_stats_status('postgres', $dboid, 'f');
 
@@ -102,16 +103,16 @@ test_standby_db_stats_status('postgres', $dboid, 'f');
 # NB: Can't test database stats, they're immediately repopulated when
 # reconnecting...
 $sect = "pre restart";
-($dboid, $tableoid, $funcoid) = populate_standby_stats('postgres', 'public');
+($dboid, $tableoid, $indexoid, $funcoid) = populate_standby_stats('postgres', 'public');
 test_standby_func_tab_stats_status('postgres',
-	$dboid, $tableoid, $funcoid, 't');
+	$dboid, $tableoid, $indexoid, $funcoid, 't');
 
 $node_standby->restart();
 
 $sect = "post non-immediate";
 
 test_standby_func_tab_stats_status('postgres',
-	$dboid, $tableoid, $funcoid, 't');
+	$dboid, $tableoid, $indexoid, $funcoid, 't');
 
 # but gone after an immediate restart
 $node_standby->stop('immediate');
@@ -120,7 +121,7 @@ $node_standby->start();
 $sect = "post immediate restart";
 
 test_standby_func_tab_stats_status('postgres',
-	$dboid, $tableoid, $funcoid, 'f');
+	$dboid, $tableoid, $indexoid, $funcoid, 'f');
 
 
 done_testing();
@@ -134,6 +135,9 @@ sub populate_standby_stats
 	$node_primary->safe_psql($connect_db,
 		"CREATE TABLE $schema.drop_tab_test1 AS SELECT generate_series(1,100) AS a"
 	);
+	$node_primary->safe_psql($connect_db,
+		"CREATE INDEX drop_tab_test1_idx on $schema.drop_tab_test1(a);"
+	);
 	$node_primary->safe_psql($connect_db,
 		"CREATE FUNCTION $schema.drop_func_test1() RETURNS VOID AS 'select 2;' LANGUAGE SQL IMMUTABLE"
 	);
@@ -145,6 +149,8 @@ sub populate_standby_stats
 		"SELECT oid FROM pg_database WHERE datname = '$connect_db'");
 	my $tableoid = $node_standby->safe_psql($connect_db,
 		"SELECT '$schema.drop_tab_test1'::regclass::oid");
+	my $indexoid = $node_standby->safe_psql($connect_db,
+		"SELECT '$schema.drop_tab_test1_idx'::regclass::oid");
 	my $funcoid = $node_standby->safe_psql($connect_db,
 		"SELECT '$schema.drop_func_test1()'::regprocedure::oid");
 
@@ -153,7 +159,7 @@ sub populate_standby_stats
 		"SELECT * FROM $schema.drop_tab_test1");
 	$node_standby->safe_psql($connect_db, "SELECT $schema.drop_func_test1()");
 
-	return ($dboid, $tableoid, $funcoid);
+	return ($dboid, $tableoid, $indexoid, $funcoid);
 }
 
 sub drop_function_by_oid
@@ -176,14 +182,26 @@ sub drop_table_by_oid
 	$node_primary->safe_psql($connect_db, "DROP TABLE $table_name");
 }
 
+sub drop_index_by_oid
+{
+	my ($connect_db, $indexoid) = @_;
+
+	# Get index name from returned oid
+	my $index_name =
+	  $node_primary->safe_psql($connect_db, "SELECT '$indexoid'::regclass");
+	$node_primary->safe_psql($connect_db, "DROP index $index_name");
+}
+
 sub test_standby_func_tab_stats_status
 {
 	local $Test::Builder::Level = $Test::Builder::Level + 1;
-	my ($connect_db, $dboid, $tableoid, $funcoid, $present) = @_;
+	my ($connect_db, $dboid, $tableoid, $indexoid, $funcoid, $present) = @_;
 
-	my %expected = (rel => $present, func => $present);
+	my %expected = (idx=> $present, rel => $present, func => $present);
 	my %stats;
 
+	$stats{idx} = $node_standby->safe_psql($connect_db,
+		"SELECT pg_stat_have_stats('relation', $dboid, $indexoid)");
 	$stats{rel} = $node_standby->safe_psql($connect_db,
 		"SELECT pg_stat_have_stats('relation', $dboid, $tableoid)");
 	$stats{func} = $node_standby->safe_psql($connect_db,