agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH 1/5] pg_rewind: Move syncTargetDirectory() to file_ops.c
4+ messages / 2 participants
[nested] [flat]

* [PATCH 1/5] pg_rewind: Move syncTargetDirectory() to file_ops.c
@ 2020-08-19 12:34 Heikki Linnakangas <[email protected]>
  0 siblings, 0 replies; 4+ messages in thread

From: Heikki Linnakangas @ 2020-08-19 12:34 UTC (permalink / raw)

For consistency. All the other low-level functions that operate on the
target directory are in file_ops.c.
---
 src/bin/pg_rewind/file_ops.c  | 19 +++++++++++++++++++
 src/bin/pg_rewind/file_ops.h  |  1 +
 src/bin/pg_rewind/pg_rewind.c | 22 +---------------------
 src/bin/pg_rewind/pg_rewind.h |  1 +
 4 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c
index b3bf091c546..55439db20ba 100644
--- a/src/bin/pg_rewind/file_ops.c
+++ b/src/bin/pg_rewind/file_ops.c
@@ -19,6 +19,7 @@
 #include <unistd.h>
 
 #include "common/file_perm.h"
+#include "common/file_utils.h"
 #include "file_ops.h"
 #include "filemap.h"
 #include "pg_rewind.h"
@@ -266,6 +267,24 @@ remove_target_symlink(const char *path)
 				 dstpath);
 }
 
+/*
+ * Sync target data directory to ensure that modifications are safely on disk.
+ *
+ * We do this once, for the whole data directory, for performance reasons.  At
+ * the end of pg_rewind's run, the kernel is likely to already have flushed
+ * most dirty buffers to disk.  Additionally fsync_pgdata uses a two-pass
+ * approach (only initiating writeback in the first pass), which often reduces
+ * the overall amount of IO noticeably.
+ */
+void
+sync_target_dir(void)
+{
+	if (!do_sync || dry_run)
+		return;
+
+	fsync_pgdata(datadir_target, PG_VERSION_NUM);
+}
+
 
 /*
  * Read a file into memory. The file to be read is <datadir>/<path>.
diff --git a/src/bin/pg_rewind/file_ops.h b/src/bin/pg_rewind/file_ops.h
index 025f24141c9..d8466385cf5 100644
--- a/src/bin/pg_rewind/file_ops.h
+++ b/src/bin/pg_rewind/file_ops.h
@@ -19,6 +19,7 @@ extern void remove_target_file(const char *path, bool missing_ok);
 extern void truncate_target_file(const char *path, off_t newsize);
 extern void create_target(file_entry_t *t);
 extern void remove_target(file_entry_t *t);
+extern void sync_target_dir(void);
 
 extern char *slurpFile(const char *datadir, const char *path, size_t *filesize);
 
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 23fc749e445..c9b9e480c0f 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -20,7 +20,6 @@
 #include "catalog/pg_control.h"
 #include "common/controldata_utils.h"
 #include "common/file_perm.h"
-#include "common/file_utils.h"
 #include "common/restricted_token.h"
 #include "common/string.h"
 #include "fe_utils/recovery_gen.h"
@@ -38,7 +37,6 @@ static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli,
 
 static void digestControlFile(ControlFileData *ControlFile, char *source,
 							  size_t size);
-static void syncTargetDirectory(void);
 static void getRestoreCommand(const char *argv0);
 static void sanityChecks(void);
 static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex);
@@ -455,7 +453,7 @@ main(int argc, char **argv)
 
 	if (showprogress)
 		pg_log_info("syncing target data directory");
-	syncTargetDirectory();
+	sync_target_dir();
 
 	if (writerecoveryconf && !dry_run)
 		WriteRecoveryConfig(conn, datadir_target,
@@ -803,24 +801,6 @@ digestControlFile(ControlFileData *ControlFile, char *src, size_t size)
 	checkControlFile(ControlFile);
 }
 
-/*
- * Sync target data directory to ensure that modifications are safely on disk.
- *
- * We do this once, for the whole data directory, for performance reasons.  At
- * the end of pg_rewind's run, the kernel is likely to already have flushed
- * most dirty buffers to disk.  Additionally fsync_pgdata uses a two-pass
- * approach (only initiating writeback in the first pass), which often reduces
- * the overall amount of IO noticeably.
- */
-static void
-syncTargetDirectory(void)
-{
-	if (!do_sync || dry_run)
-		return;
-
-	fsync_pgdata(datadir_target, PG_VERSION_NUM);
-}
-
 /*
  * Get value of GUC parameter restore_command from the target cluster.
  *
diff --git a/src/bin/pg_rewind/pg_rewind.h b/src/bin/pg_rewind/pg_rewind.h
index 8a9319ed675..67f90c2a38c 100644
--- a/src/bin/pg_rewind/pg_rewind.h
+++ b/src/bin/pg_rewind/pg_rewind.h
@@ -24,6 +24,7 @@ extern char *datadir_source;
 extern char *connstr_source;
 extern bool showprogress;
 extern bool dry_run;
+extern bool do_sync;
 extern int	WalSegSz;
 
 /* Target history */
-- 
2.20.1


--------------D93EDEBFB124D563B723F4BD
Content-Type: text/x-patch; charset=UTF-8;
 name="0002-Refactor-pg_rewind-for-more-clear-decision-making.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename*0="0002-Refactor-pg_rewind-for-more-clear-decision-making.patch"



^ permalink  raw  reply  [nested|flat] 4+ messages in thread

* [PATCH v68 19/31] pgstat: test: test stats interactions with streaming replication.
@ 2022-03-21 19:58 Andres Freund <[email protected]>
  0 siblings, 0 replies; 4+ messages in thread

From: Andres Freund @ 2022-03-21 19:58 UTC (permalink / raw)

Author: Melanie Plageman <[email protected]>
Discussion: https://postgr.es/m/[email protected]
---
 .../recovery/t/030_stats_cleanup_replica.pl   | 228 ++++++++++++++++++
 1 file changed, 228 insertions(+)
 create mode 100644 src/test/recovery/t/030_stats_cleanup_replica.pl

diff --git a/src/test/recovery/t/030_stats_cleanup_replica.pl b/src/test/recovery/t/030_stats_cleanup_replica.pl
new file mode 100644
index 00000000000..ea79e990395
--- /dev/null
+++ b/src/test/recovery/t/030_stats_cleanup_replica.pl
@@ -0,0 +1,228 @@
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# Tests that statistics are removed from a physical replica after being dropped
+# on the primary
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+# Initialize primary node
+my $node_primary = PostgreSQL::Test::Cluster->new('primary');
+# A specific role is created to perform some tests related to replication,
+# and it needs proper authentication configuration.
+$node_primary->init(
+	allows_streaming => 1,
+	auth_extra       => [ '--create-role', 'repl_role' ]);
+$node_primary->start;
+my $backup_name = 'my_backup';
+
+# Set track_functions to all on primary
+$node_primary->append_conf('postgresql.conf', "track_functions = 'all'");
+$node_primary->reload;
+
+# Take backup
+$node_primary->backup($backup_name);
+
+# Create streaming standby linking to primary
+my $node_standby = PostgreSQL::Test::Cluster->new('standby');
+$node_standby->init_from_backup($node_primary, $backup_name,
+	has_streaming => 1);
+$node_standby->start;
+
+sub populate_standby_stats
+{
+	my ($node_primary, $node_standby, $connect_db, $schema) = @_;
+	# Create table on primary
+	$node_primary->safe_psql($connect_db,
+		"CREATE TABLE $schema.drop_tab_test1 AS SELECT generate_series(1,100) AS a"
+	);
+
+	# Create function on primary
+	$node_primary->safe_psql($connect_db,
+		"CREATE FUNCTION $schema.drop_func_test1() RETURNS VOID AS 'select 2;' LANGUAGE SQL IMMUTABLE"
+	);
+
+	# Wait for catchup
+	my $primary_lsn = $node_primary->lsn('write');
+	$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+	# Get database oid
+	my $dboid = $node_standby->safe_psql($connect_db,
+		"SELECT oid FROM pg_database WHERE datname = '$connect_db'");
+
+	# Get table oid
+	my $tableoid = $node_standby->safe_psql($connect_db,
+		"SELECT '$schema.drop_tab_test1'::regclass::oid");
+
+	# Do scan on standby
+	$node_standby->safe_psql($connect_db,
+		"SELECT * FROM $schema.drop_tab_test1");
+
+	# Get function oid
+	my $funcoid = $node_standby->safe_psql($connect_db,
+		"SELECT '$schema.drop_func_test1()'::regprocedure::oid");
+
+	# Call function on standby
+	$node_standby->safe_psql($connect_db, "SELECT $schema.drop_func_test1()");
+
+	# Force flush of stats on standby
+	$node_standby->safe_psql($connect_db,
+		"SELECT pg_stat_force_next_flush()");
+
+	return ($dboid, $tableoid, $funcoid);
+}
+
+sub drop_function_by_oid
+{
+	my ($node_primary, $connect_db, $funcoid) = @_;
+
+	# Get function name from returned oid
+	my $func_name = $node_primary->safe_psql($connect_db,
+		"SELECT '$funcoid'::regprocedure");
+
+	# Drop function on primary
+	$node_primary->safe_psql($connect_db, "DROP FUNCTION $func_name");
+}
+
+sub drop_table_by_oid
+{
+	my ($node_primary, $connect_db, $tableoid) = @_;
+
+	# Get table name from returned oid
+	my $table_name =
+	  $node_primary->safe_psql($connect_db, "SELECT '$tableoid'::regclass");
+
+	# Drop table on primary
+	$node_primary->safe_psql($connect_db, "DROP TABLE $table_name");
+}
+
+sub test_standby_func_tab_stats_status
+{
+	local $Test::Builder::Level = $Test::Builder::Level + 1;
+	my ($node_standby, $connect_db, $dboid, $tableoid, $funcoid, $present) =
+	  @_;
+
+	is( $node_standby->safe_psql(
+			$connect_db,
+			"SELECT pg_stat_exists_stat('relation', $dboid, $tableoid)"),
+		$present,
+		"Check that table stats exist is '$present' on standby");
+
+	is( $node_standby->safe_psql(
+			$connect_db,
+			"SELECT pg_stat_exists_stat('function', $dboid, $funcoid)"),
+		$present,
+		"Check that function stats exist is '$present' on standby");
+
+	return;
+}
+
+sub test_standby_db_stats_status
+{
+	local $Test::Builder::Level = $Test::Builder::Level + 1;
+	my ($node_standby, $connect_db, $dboid, $present) = @_;
+
+	is( $node_standby->safe_psql(
+			$connect_db, "SELECT pg_stat_exists_stat('database', $dboid, 0)"),
+		$present,
+		"Check that db stats exist is '$present' on standby");
+}
+
+# Test that stats are cleaned up on standby after dropping table or function
+
+# Populate test objects
+my ($dboid, $tableoid, $funcoid) =
+  populate_standby_stats($node_primary, $node_standby, 'postgres', 'public');
+
+# Test that the stats are present
+test_standby_func_tab_stats_status($node_standby, 'postgres',
+	$dboid, $tableoid, $funcoid, 't');
+
+# Drop test objects
+drop_table_by_oid($node_primary, 'postgres', $tableoid);
+
+drop_function_by_oid($node_primary, 'postgres', $funcoid);
+
+# Wait for catchup
+my $primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Force flush of stats on standby
+$node_standby->safe_psql('postgres', "SELECT pg_stat_force_next_flush()");
+
+# Check table and function stats removed from standby
+test_standby_func_tab_stats_status($node_standby, 'postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+# Check that stats are cleaned up on standby after dropping schema
+
+# Create schema
+$node_primary->safe_psql('postgres', "CREATE SCHEMA drop_schema_test1");
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Populate test objects
+($dboid, $tableoid, $funcoid) = populate_standby_stats($node_primary,
+	$node_standby, 'postgres', 'drop_schema_test1');
+
+# Test that the stats are present
+test_standby_func_tab_stats_status($node_standby, 'postgres',
+	$dboid, $tableoid, $funcoid, 't');
+
+# Drop schema
+$node_primary->safe_psql('postgres', "DROP SCHEMA drop_schema_test1 CASCADE");
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Force flush of stats on standby
+$node_standby->safe_psql('postgres', "SELECT pg_stat_force_next_flush()");
+
+# Check table and function stats removed from standby
+test_standby_func_tab_stats_status($node_standby, 'postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+# Test that stats are cleaned up on standby after dropping database
+
+# Create the database
+$node_primary->safe_psql('postgres', "CREATE DATABASE test");
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Populate test objects
+($dboid, $tableoid, $funcoid) =
+  populate_standby_stats($node_primary, $node_standby, 'test', 'public');
+
+# Test that the stats are present
+test_standby_func_tab_stats_status($node_standby, 'test',
+	$dboid, $tableoid, $funcoid, 't');
+
+test_standby_db_stats_status($node_standby, 'test', $dboid, 't');
+
+# Drop db 'test' on primary
+$node_primary->safe_psql('postgres', "DROP DATABASE test");
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Force flush of stats on standby
+$node_standby->safe_psql('postgres', "SELECT pg_stat_force_next_flush()");
+
+# Test that the stats were cleaned up on standby
+# Note that this connects to 'postgres' but provides the dboid of dropped db
+# 'test' which was returned by previous routine
+test_standby_func_tab_stats_status($node_standby, 'postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+test_standby_db_stats_status($node_standby, 'postgres', $dboid, 'f');
+
+done_testing();
-- 
2.35.1.677.gabf474a5dd


--c4n45bccvxafocvc
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v68-0020-pgstat-test-stats-handling-of-restarts-including.patch"



^ permalink  raw  reply  [nested|flat] 4+ messages in thread

* [PATCH v69 15/28] pgstat: test: test stats interactions with streaming replication.
@ 2022-03-21 19:58 Andres Freund <[email protected]>
  0 siblings, 0 replies; 4+ messages in thread

From: Andres Freund @ 2022-03-21 19:58 UTC (permalink / raw)

Author: Melanie Plageman <[email protected]>
Discussion: https://postgr.es/m/[email protected]
---
 .../recovery/t/030_stats_cleanup_replica.pl   | 218 ++++++++++++++++++
 1 file changed, 218 insertions(+)
 create mode 100644 src/test/recovery/t/030_stats_cleanup_replica.pl

diff --git a/src/test/recovery/t/030_stats_cleanup_replica.pl b/src/test/recovery/t/030_stats_cleanup_replica.pl
new file mode 100644
index 00000000000..be7e62a9cb4
--- /dev/null
+++ b/src/test/recovery/t/030_stats_cleanup_replica.pl
@@ -0,0 +1,218 @@
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# Tests that statistics are removed from a physical replica after being dropped
+# on the primary
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+# Initialize primary node
+my $node_primary = PostgreSQL::Test::Cluster->new('primary');
+# A specific role is created to perform some tests related to replication,
+# and it needs proper authentication configuration.
+$node_primary->init(allows_streaming => 1);
+
+# Set track_functions to all on primary
+$node_primary->append_conf('postgresql.conf', "track_functions = 'all'");
+$node_primary->start;
+
+# Take backup
+my $backup_name = 'my_backup';
+$node_primary->backup($backup_name);
+
+# Create streaming standby linking to primary
+my $node_standby = PostgreSQL::Test::Cluster->new('standby');
+$node_standby->init_from_backup($node_primary, $backup_name,
+	has_streaming => 1);
+$node_standby->start;
+
+my $sect = 'initial';
+
+sub populate_standby_stats
+{
+	my ($connect_db, $schema) = @_;
+	# Create table on primary
+	$node_primary->safe_psql($connect_db,
+		"CREATE TABLE $schema.drop_tab_test1 AS SELECT generate_series(1,100) AS a"
+	);
+
+	# Create function on primary
+	$node_primary->safe_psql($connect_db,
+		"CREATE FUNCTION $schema.drop_func_test1() RETURNS VOID AS 'select 2;' LANGUAGE SQL IMMUTABLE"
+	);
+
+	# Wait for catchup
+	my $primary_lsn = $node_primary->lsn('write');
+	$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+	# Get database oid
+	my $dboid = $node_standby->safe_psql($connect_db,
+		"SELECT oid FROM pg_database WHERE datname = '$connect_db'");
+
+	# Get table oid
+	my $tableoid = $node_standby->safe_psql($connect_db,
+		"SELECT '$schema.drop_tab_test1'::regclass::oid");
+
+	# Do scan on standby
+	$node_standby->safe_psql($connect_db,
+		"SELECT * FROM $schema.drop_tab_test1");
+
+	# Get function oid
+	my $funcoid = $node_standby->safe_psql($connect_db,
+		"SELECT '$schema.drop_func_test1()'::regprocedure::oid");
+
+	# Call function on standby
+	$node_standby->safe_psql($connect_db, "SELECT $schema.drop_func_test1()");
+
+	return ($dboid, $tableoid, $funcoid);
+}
+
+sub drop_function_by_oid
+{
+	my ($connect_db, $funcoid) = @_;
+
+	# Get function name from returned oid
+	my $func_name = $node_primary->safe_psql($connect_db,
+		"SELECT '$funcoid'::regprocedure");
+
+	# Drop function on primary
+	$node_primary->safe_psql($connect_db, "DROP FUNCTION $func_name");
+}
+
+sub drop_table_by_oid
+{
+	my ($connect_db, $tableoid) = @_;
+
+	# Get table name from returned oid
+	my $table_name =
+	  $node_primary->safe_psql($connect_db, "SELECT '$tableoid'::regclass");
+
+	# Drop table on primary
+	$node_primary->safe_psql($connect_db, "DROP TABLE $table_name");
+}
+
+sub test_standby_func_tab_stats_status
+{
+	local $Test::Builder::Level = $Test::Builder::Level + 1;
+	my ($connect_db, $dboid, $tableoid, $funcoid, $present) = @_;
+
+	my %expected = (rel => $present, func => $present);
+	my %stats;
+
+	$stats{rel} = $node_standby->safe_psql($connect_db,
+		"SELECT pg_stat_exists_stat('relation', $dboid, $tableoid)");
+	$stats{func} = $node_standby->safe_psql($connect_db,
+		"SELECT pg_stat_exists_stat('function', $dboid, $funcoid)");
+
+	is_deeply(\%stats, \%expected, "$sect: standby stats as expected");
+
+	return;
+}
+
+sub test_standby_db_stats_status
+{
+	local $Test::Builder::Level = $Test::Builder::Level + 1;
+	my ($connect_db, $dboid, $present) = @_;
+
+	is( $node_standby->safe_psql(
+			$connect_db, "SELECT pg_stat_exists_stat('database', $dboid, 0)"),
+		$present,
+		"$sect: standby db stats as expected");
+}
+
+# Test that stats are cleaned up on standby after dropping table or function
+
+# Populate test objects
+my ($dboid, $tableoid, $funcoid) =
+  populate_standby_stats('postgres', 'public');
+
+# Test that the stats are present
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 't');
+
+# Drop test objects
+drop_table_by_oid('postgres', $tableoid);
+
+drop_function_by_oid('postgres', $funcoid);
+
+$sect = 'post drop';
+
+# Wait for catchup
+my $primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Check table and function stats removed from standby
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+# Check that stats are cleaned up on standby after dropping schema
+
+$sect = "schema creation";
+
+# Create schema
+$node_primary->safe_psql('postgres', "CREATE SCHEMA drop_schema_test1");
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Populate test objects
+($dboid, $tableoid, $funcoid) =
+  populate_standby_stats('postgres', 'drop_schema_test1');
+
+# Test that the stats are present
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 't');
+
+# Drop schema
+$node_primary->safe_psql('postgres', "DROP SCHEMA drop_schema_test1 CASCADE");
+
+$sect = "post schema drop";
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Check table and function stats removed from standby
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+# Test that stats are cleaned up on standby after dropping database
+
+# Create the database
+$node_primary->safe_psql('postgres', "CREATE DATABASE test");
+
+$sect = "createdb";
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Populate test objects
+($dboid, $tableoid, $funcoid) = populate_standby_stats('test', 'public');
+
+# Test that the stats are present
+test_standby_func_tab_stats_status('test', $dboid, $tableoid, $funcoid, 't');
+
+test_standby_db_stats_status('test', $dboid, 't');
+
+# Drop db 'test' on primary
+$node_primary->safe_psql('postgres', "DROP DATABASE test");
+$sect = "post dropdb";
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Test that the stats were cleaned up on standby
+# Note that this connects to 'postgres' but provides the dboid of dropped db
+# 'test' which was returned by previous routine
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+test_standby_db_stats_status('postgres', $dboid, 'f');
+
+done_testing();
-- 
2.35.1.677.gabf474a5dd


--be3jiks7ge4r32o3
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v69-0016-pgstat-test-stats-handling-of-restarts-including.patch"



^ permalink  raw  reply  [nested|flat] 4+ messages in thread

* [PATCH v70 20/27] pgstat: test: test stats interactions with streaming replication.
@ 2022-03-21 19:58 Andres Freund <[email protected]>
  0 siblings, 0 replies; 4+ messages in thread

From: Andres Freund @ 2022-03-21 19:58 UTC (permalink / raw)

Author: Melanie Plageman <[email protected]>
Discussion: https://postgr.es/m/[email protected]
---
 .../recovery/t/030_stats_cleanup_replica.pl   | 243 ++++++++++++++++++
 1 file changed, 243 insertions(+)
 create mode 100644 src/test/recovery/t/030_stats_cleanup_replica.pl

diff --git a/src/test/recovery/t/030_stats_cleanup_replica.pl b/src/test/recovery/t/030_stats_cleanup_replica.pl
new file mode 100644
index 00000000000..6b8998e5da9
--- /dev/null
+++ b/src/test/recovery/t/030_stats_cleanup_replica.pl
@@ -0,0 +1,243 @@
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# Tests that statistics are removed from a physical replica after being dropped
+# on the primary
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+# Initialize primary node
+my $node_primary = PostgreSQL::Test::Cluster->new('primary');
+# A specific role is created to perform some tests related to replication,
+# and it needs proper authentication configuration.
+$node_primary->init(allows_streaming => 1);
+
+# Set track_functions to all on primary
+$node_primary->append_conf('postgresql.conf', "track_functions = 'all'");
+$node_primary->start;
+
+# Take backup
+my $backup_name = 'my_backup';
+$node_primary->backup($backup_name);
+
+# Create streaming standby linking to primary
+my $node_standby = PostgreSQL::Test::Cluster->new('standby');
+$node_standby->init_from_backup($node_primary, $backup_name,
+	has_streaming => 1);
+$node_standby->start;
+
+my $sect = 'initial';
+
+sub populate_standby_stats
+{
+	my ($connect_db, $schema) = @_;
+	# Create table on primary
+	$node_primary->safe_psql($connect_db,
+		"CREATE TABLE $schema.drop_tab_test1 AS SELECT generate_series(1,100) AS a"
+	);
+
+	# Create function on primary
+	$node_primary->safe_psql($connect_db,
+		"CREATE FUNCTION $schema.drop_func_test1() RETURNS VOID AS 'select 2;' LANGUAGE SQL IMMUTABLE"
+	);
+
+	# Wait for catchup
+	my $primary_lsn = $node_primary->lsn('write');
+	$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+	# Get database oid
+	my $dboid = $node_standby->safe_psql($connect_db,
+		"SELECT oid FROM pg_database WHERE datname = '$connect_db'");
+
+	# Get table oid
+	my $tableoid = $node_standby->safe_psql($connect_db,
+		"SELECT '$schema.drop_tab_test1'::regclass::oid");
+
+	# Do scan on standby
+	$node_standby->safe_psql($connect_db,
+		"SELECT * FROM $schema.drop_tab_test1");
+
+	# Get function oid
+	my $funcoid = $node_standby->safe_psql($connect_db,
+		"SELECT '$schema.drop_func_test1()'::regprocedure::oid");
+
+	# Call function on standby
+	$node_standby->safe_psql($connect_db, "SELECT $schema.drop_func_test1()");
+
+	return ($dboid, $tableoid, $funcoid);
+}
+
+sub drop_function_by_oid
+{
+	my ($connect_db, $funcoid) = @_;
+
+	# Get function name from returned oid
+	my $func_name = $node_primary->safe_psql($connect_db,
+		"SELECT '$funcoid'::regprocedure");
+
+	# Drop function on primary
+	$node_primary->safe_psql($connect_db, "DROP FUNCTION $func_name");
+}
+
+sub drop_table_by_oid
+{
+	my ($connect_db, $tableoid) = @_;
+
+	# Get table name from returned oid
+	my $table_name =
+	  $node_primary->safe_psql($connect_db, "SELECT '$tableoid'::regclass");
+
+	# Drop table on primary
+	$node_primary->safe_psql($connect_db, "DROP TABLE $table_name");
+}
+
+sub test_standby_func_tab_stats_status
+{
+	local $Test::Builder::Level = $Test::Builder::Level + 1;
+	my ($connect_db, $dboid, $tableoid, $funcoid, $present) = @_;
+
+	my %expected = (rel => $present, func => $present);
+	my %stats;
+
+	$stats{rel} = $node_standby->safe_psql($connect_db,
+		"SELECT pg_stat_exists_stat('relation', $dboid, $tableoid)");
+	$stats{func} = $node_standby->safe_psql($connect_db,
+		"SELECT pg_stat_exists_stat('function', $dboid, $funcoid)");
+
+	is_deeply(\%stats, \%expected, "$sect: standby stats as expected");
+
+	return;
+}
+
+sub test_standby_db_stats_status
+{
+	local $Test::Builder::Level = $Test::Builder::Level + 1;
+	my ($connect_db, $dboid, $present) = @_;
+
+	is( $node_standby->safe_psql(
+			$connect_db, "SELECT pg_stat_exists_stat('database', $dboid, 0)"),
+		$present,
+		"$sect: standby db stats as expected");
+}
+
+# Test that stats are cleaned up on standby after dropping table or function
+
+# Populate test objects
+my ($dboid, $tableoid, $funcoid) =
+  populate_standby_stats('postgres', 'public');
+
+# Test that the stats are present
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 't');
+
+# Drop test objects
+drop_table_by_oid('postgres', $tableoid);
+
+drop_function_by_oid('postgres', $funcoid);
+
+$sect = 'post drop';
+
+# Wait for catchup
+my $primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Check table and function stats removed from standby
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+# Check that stats are cleaned up on standby after dropping schema
+
+$sect = "schema creation";
+
+# Create schema
+$node_primary->safe_psql('postgres', "CREATE SCHEMA drop_schema_test1");
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Populate test objects
+($dboid, $tableoid, $funcoid) =
+  populate_standby_stats('postgres', 'drop_schema_test1');
+
+# Test that the stats are present
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 't');
+
+# Drop schema
+$node_primary->safe_psql('postgres', "DROP SCHEMA drop_schema_test1 CASCADE");
+
+$sect = "post schema drop";
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Check table and function stats removed from standby
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+# Test that stats are cleaned up on standby after dropping database
+
+# Create the database
+$node_primary->safe_psql('postgres', "CREATE DATABASE test");
+
+$sect = "createdb";
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Populate test objects
+($dboid, $tableoid, $funcoid) = populate_standby_stats('test', 'public');
+
+# Test that the stats are present
+test_standby_func_tab_stats_status('test', $dboid, $tableoid, $funcoid, 't');
+
+test_standby_db_stats_status('test', $dboid, 't');
+
+# Drop db 'test' on primary
+$node_primary->safe_psql('postgres', "DROP DATABASE test");
+$sect = "post dropdb";
+
+# Wait for catchup
+$primary_lsn = $node_primary->lsn('write');
+$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
+
+# Test that the stats were cleaned up on standby
+# Note that this connects to 'postgres' but provides the dboid of dropped db
+# 'test' which was returned by previous routine
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+test_standby_db_stats_status('postgres', $dboid, 'f');
+
+# verify that stats persist across graceful restarts on a replica
+
+# NB: Can't test database stats, they're immediately repopulated when
+# reconnecting...
+$sect = "pre restart";
+($dboid, $tableoid, $funcoid) = populate_standby_stats('postgres', 'public');
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 't');
+
+$node_standby->restart();
+
+$sect = "post non-immediate";
+
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 't');
+
+# but gone after an immediate restart
+$node_standby->stop('immediate');
+$node_standby->start();
+
+$sect = "post immediate restart";
+
+test_standby_func_tab_stats_status('postgres',
+	$dboid, $tableoid, $funcoid, 'f');
+
+done_testing();
-- 
2.35.1.677.gabf474a5dd


--vl7on5vfmrsyxmos
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v70-0021-pgstat-test-subscriber-stats-reset-and-drop.patch"



^ permalink  raw  reply  [nested|flat] 4+ messages in thread


end of thread, other threads:[~2022-03-21 19:58 UTC | newest]

Thread overview: 4+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2020-08-19 12:34 [PATCH 1/5] pg_rewind: Move syncTargetDirectory() to file_ops.c Heikki Linnakangas <[email protected]>
2022-03-21 19:58 [PATCH v68 19/31] pgstat: test: test stats interactions with streaming replication. Andres Freund <[email protected]>
2022-03-21 19:58 [PATCH v69 15/28] pgstat: test: test stats interactions with streaming replication. Andres Freund <[email protected]>
2022-03-21 19:58 [PATCH v70 20/27] pgstat: test: test stats interactions with streaming replication. Andres Freund <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox