agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v25 4/5] Add ALTER INDEX ... ALTER COLLATION ... REFRESH VERSION.
4+ messages / 2 participants
[nested] [flat]

* [PATCH v25 4/5] Add ALTER INDEX ... ALTER COLLATION ... REFRESH VERSION.
@ 2019-12-11 12:54  Julien Rouhaud <[email protected]>
  0 siblings, 0 replies; 4+ messages in thread

From: Julien Rouhaud @ 2019-12-11 12:54 UTC (permalink / raw)

This command allows privileged users to specify that the currently installed
collation version, for a specific collation, is binary compatible with the one
that was installed when the specified index was built.  This provides a way to
clear warnings about potentially corrupted indexes without having to use
REINDEX.

Author: Julien Rouhaud
Reviewed-by: Laurenz Albe, Thomas Munro and Peter Eisentraut
Discussion: https://postgr.es/m/CAEepm%3D0uEQCpfq_%2BLYFBdArCe4Ot98t1aR4eYiYTe%3DyavQygiQ%40mail.gmail.com
---
 doc/src/sgml/ref/alter_index.sgml             | 17 +++++++
 src/backend/catalog/index.c                   |  2 +-
 src/backend/commands/tablecmds.c              | 46 +++++++++++++++++++
 src/backend/nodes/copyfuncs.c                 |  1 +
 src/backend/parser/gram.y                     |  8 ++++
 src/bin/psql/tab-complete.c                   | 27 ++++++++++-
 src/include/catalog/index.h                   |  3 ++
 src/include/nodes/parsenodes.h                |  4 +-
 .../regress/expected/collate.icu.utf8.out     | 20 ++++++++
 src/test/regress/sql/collate.icu.utf8.sql     | 11 +++++
 10 files changed, 136 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/ref/alter_index.sgml b/doc/src/sgml/ref/alter_index.sgml
index a5e3b06ee4..03355164b3 100644
--- a/doc/src/sgml/ref/alter_index.sgml
+++ b/doc/src/sgml/ref/alter_index.sgml
@@ -25,6 +25,7 @@ ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> RENA
 ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> SET TABLESPACE <replaceable class="parameter">tablespace_name</replaceable>
 ALTER INDEX <replaceable class="parameter">name</replaceable> ATTACH PARTITION <replaceable class="parameter">index_name</replaceable>
 ALTER INDEX <replaceable class="parameter">name</replaceable> DEPENDS ON EXTENSION <replaceable class="parameter">extension_name</replaceable>
+ALTER INDEX <replaceable class="parameter">name</replaceable> ALTER COLLATION <replaceable class="parameter">collation_name</replaceable> REFRESH VERSION
 ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> SET ( <replaceable class="parameter">storage_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )
 ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> RESET ( <replaceable class="parameter">storage_parameter</replaceable> [, ... ] )
 ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> ALTER [ COLUMN ] <replaceable class="parameter">column_number</replaceable>
@@ -112,6 +113,22 @@ ALTER INDEX ALL IN TABLESPACE <replaceable class="parameter">name</replaceable>
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><literal>ALTER COLLATION <replaceable class="parameter">collation_name</replaceable> REFRESH VERSION</literal></term>
+    <listitem>
+     <para>
+      This command declares that the index is compatible with the currently
+      installed version of a collation that determines its order.  It is used
+      to silence warnings caused by collation version incompatibilities and
+      should be issued only if the collation ordering is known not to have
+      changed since the index was last built.  Be aware that incorrect use of
+      this command can hide index corruption.  If you don't know whether a
+      collation's definition has changed, using <xref linkend="sql-reindex"/>
+      is a safe alternative.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><literal>SET ( <replaceable class="parameter">storage_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )</literal></term>
     <listitem>
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index e85aeb5502..ef2b896b6f 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3156,7 +3156,7 @@ index_build(Relation heapRelation,
 	SetUserIdAndSecContext(save_userid, save_sec_context);
 }
 
-static char *
+char *
 index_force_collation_version(const ObjectAddress *otherObject,
 							  const char *version,
 							  void *userdata)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f79044f39f..cdf3cbf5b1 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -93,6 +93,7 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/partcache.h"
+#include "utils/pg_locale.h"
 #include "utils/relcache.h"
 #include "utils/ruleutils.h"
 #include "utils/snapmgr.h"
@@ -556,6 +557,7 @@ static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
 								  Relation partitionTbl);
 static List *GetParentedForeignKeyRefs(Relation partition);
 static void ATDetachCheckNoForeignKeyRefs(Relation partition);
+static void ATExecAlterCollationRefreshVersion(Relation rel, List *coll);
 
 
 /* ----------------------------------------------------------------
@@ -3926,6 +3928,10 @@ AlterTableGetLockLevel(List *cmds)
 				cmd_lockmode = AccessShareLock;
 				break;
 
+			case AT_AlterCollationRefreshVersion:
+				cmd_lockmode = AccessExclusiveLock;
+				break;
+
 			default:			/* oops */
 				elog(ERROR, "unrecognized alter table type: %d",
 					 (int) cmd->subtype);
@@ -4093,6 +4099,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
 			/* This command never recurses */
 			pass = AT_PASS_MISC;
 			break;
+		case AT_AlterCollationRefreshVersion:	/* ALTER COLLATION ... REFRESH
+												 * VERSION */
+			ATSimplePermissions(rel, ATT_INDEX);
+			/* This command never recurses */
+			pass = AT_PASS_MISC;
+			break;
 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
@@ -4659,6 +4671,11 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
 			ATExecDetachPartition(rel, ((PartitionCmd *) cmd->def)->name);
 			break;
+		case AT_AlterCollationRefreshVersion:
+			/* ATPrepCmd ensured it must be an index */
+			Assert(rel->rd_rel->relkind == RELKIND_INDEX);
+			ATExecAlterCollationRefreshVersion(rel, cmd->object);
+			break;
 		default:				/* oops */
 			elog(ERROR, "unrecognized alter table type: %d",
 				 (int) cmd->subtype);
@@ -17477,3 +17494,32 @@ ATDetachCheckNoForeignKeyRefs(Relation partition)
 		table_close(rel, NoLock);
 	}
 }
+
+/* Execute an ALTER INDEX ... ALTER COLLATION ... REFRESH VERSION
+ *
+ * This override an existing dependency on a specific collation for a specific
+ * index to depend on the current collation version.
+ */
+static void
+ATExecAlterCollationRefreshVersion(Relation rel, List *coll)
+{
+	ObjectAddress object;
+	NewCollationVersionDependency forced_dependency;
+
+	Assert(coll != NIL);
+	forced_dependency.oid = get_collation_oid(coll, false);
+
+	/* Retrieve the current version for the CURRENT VERSION case. */
+	Assert(OidIsValid(forced_dependency.oid));
+	forced_dependency.version =
+		get_collation_version_for_oid(forced_dependency.oid);
+
+	object.classId = RelationRelationId;
+	object.objectId = rel->rd_id;
+	object.objectSubId = 0;
+	visitDependentObjects(&object, &index_force_collation_version,
+						  &forced_dependency);
+
+	/* Invalidate the index relcache */
+	CacheInvalidateRelcache(rel);
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 5cbbe3ba2e..ebf9118f4f 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3217,6 +3217,7 @@ _copyAlterTableCmd(const AlterTableCmd *from)
 
 	COPY_SCALAR_FIELD(subtype);
 	COPY_STRING_FIELD(name);
+	COPY_NODE_FIELD(object);
 	COPY_SCALAR_FIELD(num);
 	COPY_NODE_FIELD(newowner);
 	COPY_NODE_FIELD(def);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c43b16037e..68934bfeb1 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -2594,6 +2594,14 @@ alter_table_cmd:
 					n->subtype = AT_NoForceRowSecurity;
 					$$ = (Node *)n;
 				}
+			/* ALTER INDEX <name> ALTER COLLATION ... REFRESH VERSION */
+			| ALTER COLLATION any_name REFRESH VERSION_P
+				{
+					AlterTableCmd *n = makeNode(AlterTableCmd);
+					n->subtype = AT_AlterCollationRefreshVersion;
+					n->object = $3;
+					$$ = (Node *)n;
+				}
 			| alter_generic_options
 				{
 					AlterTableCmd *n = makeNode(AlterTableCmd);
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index eb018854a5..ec0ef1feae 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -45,6 +45,7 @@
 
 #include "catalog/pg_am_d.h"
 #include "catalog/pg_class_d.h"
+#include "catalog/pg_collation_d.h"
 #include "common.h"
 #include "libpq-fe.h"
 #include "pqexpbuffer.h"
@@ -814,6 +815,20 @@ static const SchemaQuery Query_for_list_of_statistics = {
 "       (SELECT tgrelid FROM pg_catalog.pg_trigger "\
 "         WHERE pg_catalog.quote_ident(tgname)='%s')"
 
+/* the silly-looking length condition is just to eat up the current word */
+#define Query_for_list_of_colls_for_one_index \
+" SELECT DISTINCT pg_catalog.quote_ident(coll.collname) " \
+"   FROM pg_catalog.pg_depend d, pg_catalog.pg_collation coll, " \
+"     pg_catalog.pg_class c" \
+" WHERE (%d = pg_catalog.length('%s'))" \
+"   AND d.refclassid = " CppAsString2(CollationRelationId) \
+"   AND d.refobjid = coll.oid " \
+"   AND d.classid = " CppAsString2(RelationRelationId) \
+"   AND d.objid = c.oid " \
+"   AND c.relkind = " CppAsString2(RELKIND_INDEX) \
+"   AND pg_catalog.pg_table_is_visible(c.oid) " \
+"   AND c.relname = '%s'"
+
 #define Query_for_list_of_ts_configurations \
 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
@@ -1709,7 +1724,8 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER INDEX <name> */
 	else if (Matches("ALTER", "INDEX", MatchAny))
 		COMPLETE_WITH("ALTER COLUMN", "OWNER TO", "RENAME TO", "SET",
-					  "RESET", "ATTACH PARTITION", "DEPENDS", "NO DEPENDS");
+					  "RESET", "ATTACH PARTITION", "DEPENDS", "NO DEPENDS",
+					  "ALTER COLLATION");
 	else if (Matches("ALTER", "INDEX", MatchAny, "ATTACH"))
 		COMPLETE_WITH("PARTITION");
 	else if (Matches("ALTER", "INDEX", MatchAny, "ATTACH", "PARTITION"))
@@ -1759,6 +1775,15 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH("ON EXTENSION");
 	else if (Matches("ALTER", "INDEX", MatchAny, "DEPENDS"))
 		COMPLETE_WITH("ON EXTENSION");
+	/* ALTER INDEX <name> ALTER COLLATION */
+	else if (Matches("ALTER", "INDEX", MatchAny, "ALTER", "COLLATION"))
+	{
+		completion_info_charp = prev4_wd;
+		COMPLETE_WITH_QUERY(Query_for_list_of_colls_for_one_index);
+	}
+	/* ALTER INDEX <name> ALTER COLLATION <name> */
+	else if (Matches("ALTER", "INDEX", MatchAny, "ALTER", "COLLATION", MatchAny))
+		COMPLETE_WITH("REFRESH VERSION");
 
 	/* ALTER LANGUAGE <name> */
 	else if (Matches("ALTER", "LANGUAGE", MatchAny))
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 9b4de26514..46d5df1613 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -123,6 +123,9 @@ extern void FormIndexDatum(IndexInfo *indexInfo,
 
 extern void index_check_collation_versions(Oid relid);
 
+extern char *index_force_collation_version(const ObjectAddress *otherObject,
+										   const char *version,
+										   void *userdata);
 extern void index_force_collation_versions(Oid indexid, Oid coll,
 										   char *version);
 
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 7a23fb7529..423f33b72c 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1847,7 +1847,8 @@ typedef enum AlterTableType
 	AT_DetachPartition,			/* DETACH PARTITION */
 	AT_AddIdentity,				/* ADD IDENTITY */
 	AT_SetIdentity,				/* SET identity column options */
-	AT_DropIdentity				/* DROP IDENTITY */
+	AT_DropIdentity,			/* DROP IDENTITY */
+	AT_AlterCollationRefreshVersion	/* ALTER COLLATION ... REFRESH VERSION */
 } AlterTableType;
 
 typedef struct ReplicaIdentityStmt
@@ -1863,6 +1864,7 @@ typedef struct AlterTableCmd	/* one subcommand of an ALTER TABLE */
 	AlterTableType subtype;		/* Type of table alteration to apply */
 	char	   *name;			/* column, constraint, or trigger to act on,
 								 * or tablespace */
+	List	   *object;			/* collation to act on if it's a collation */
 	int16		num;			/* attribute number for columns referenced by
 								 * number */
 	RoleSpec   *newowner;
diff --git a/src/test/regress/expected/collate.icu.utf8.out b/src/test/regress/expected/collate.icu.utf8.out
index db386c1b09..adc1dddda7 100644
--- a/src/test/regress/expected/collate.icu.utf8.out
+++ b/src/test/regress/expected/collate.icu.utf8.out
@@ -2054,6 +2054,26 @@ SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version';
 -------
 (0 rows)
 
+-- Test ALTER INDEX name ALTER COLLATION name REFRESH VERSION
+UPDATE pg_depend SET refobjversion = 'not a version'
+WHERE refclassid = 'pg_collation'::regclass
+AND objid::regclass::text = 'icuidx17_part'
+AND refobjversion IS NOT NULL;
+SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version';
+     objid     
+---------------
+ icuidx17_part
+(1 row)
+
+ALTER INDEX icuidx17_part ALTER COLLATION "en-x-icu" REFRESH VERSION;
+SELECT objid::regclass, refobjversion = 'not a version' AS ver FROM pg_depend
+WHERE refclassid = 'pg_collation'::regclass
+AND objid::regclass::text = 'icuidx17_part';
+     objid     | ver 
+---------------+-----
+ icuidx17_part | f
+(1 row)
+
 -- cleanup
 RESET search_path;
 SET client_min_messages TO warning;
diff --git a/src/test/regress/sql/collate.icu.utf8.sql b/src/test/regress/sql/collate.icu.utf8.sql
index e93530af55..b3a75b29e6 100644
--- a/src/test/regress/sql/collate.icu.utf8.sql
+++ b/src/test/regress/sql/collate.icu.utf8.sql
@@ -823,6 +823,17 @@ VACUUM FULL collate_part_1;
 
 SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version';
 
+-- Test ALTER INDEX name ALTER COLLATION name REFRESH VERSION
+UPDATE pg_depend SET refobjversion = 'not a version'
+WHERE refclassid = 'pg_collation'::regclass
+AND objid::regclass::text = 'icuidx17_part'
+AND refobjversion IS NOT NULL;
+SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version';
+ALTER INDEX icuidx17_part ALTER COLLATION "en-x-icu" REFRESH VERSION;
+SELECT objid::regclass, refobjversion = 'not a version' AS ver FROM pg_depend
+WHERE refclassid = 'pg_collation'::regclass
+AND objid::regclass::text = 'icuidx17_part';
+
 -- cleanup
 RESET search_path;
 SET client_min_messages TO warning;
-- 
2.20.1


--lrZ03NoBR/3+SXJZ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
	filename="v25-0005-doc-Add-Collation-Versions-section.patch"



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

* [PATCH v68 20/31] pgstat: test: stats handling of restarts, including crashes.
@ 2022-03-20 20:33  Melanie Plageman <[email protected]>
  0 siblings, 0 replies; 4+ messages in thread

From: Melanie Plageman @ 2022-03-20 20:33 UTC (permalink / raw)

Stats should not be restored if the db crashed. Also, ensure invalid stats
files are handled gracefully.

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

diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
new file mode 100644
index 00000000000..55534b3a68d
--- /dev/null
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -0,0 +1,305 @@
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# Tests statistics handling around restarts, including handling of crashes and
+# invalid stats files, as well as restorting stats after "normal" restarts.
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+use File::Copy;
+
+my $node = PostgreSQL::Test::Cluster->new('primary');
+$node->init(allows_streaming => 1);
+$node->start;
+$node->append_conf('postgresql.conf', "track_functions = 'all'");
+$node->reload;
+
+my $connect_db    = 'postgres';
+my $db_under_test = 'test';
+
+$node->safe_psql($connect_db, "CREATE DATABASE $db_under_test");
+
+# Create table in test db
+$node->safe_psql($db_under_test,
+	"CREATE TABLE tab_stats_crash_discard_test1 AS SELECT generate_series(1,100) AS a"
+);
+
+# Create function in test db
+$node->safe_psql($db_under_test,
+	"CREATE FUNCTION func_stats_crash_discard1() RETURNS VOID AS 'select 2;' LANGUAGE SQL IMMUTABLE"
+);
+
+# collect object oids
+my $dboid = $node->safe_psql($db_under_test,
+	"SELECT oid FROM pg_database WHERE datname = '$db_under_test'");
+my $funcoid = $node->safe_psql($db_under_test,
+	"SELECT 'func_stats_crash_discard1()'::regprocedure::oid");
+my $tableoid = $node->safe_psql($db_under_test,
+	"SELECT 'tab_stats_crash_discard_test1'::regclass::oid");
+
+# generate stats and flush them
+trigger_funcrel_stat();
+
+# verify stats objects exist
+is(exists_stat('database', $dboid, 0), 't', "Check that db stat exists.");
+is(exists_stat('function', $dboid, $funcoid),
+	't', "Check that function stat exists.");
+is(exists_stat('relation', $dboid, $tableoid),
+	't', "Check that relation stat exists.");
+
+# Regular shutdown
+$node->stop();
+
+# Backup stats files
+my $statsfile = $PostgreSQL::Test::Utils::tmp_check . '/' . "discard_stats1";
+ok(!-f "$statsfile", "Backup statsfile cannot already exist");
+
+my $datadir  = $node->data_dir();
+my $og_stats = $datadir . '/' . "pg_stat" . '/' . "pgstat.stat";
+ok(-f "$og_stats", "Origin stats file must exist");
+copy($og_stats, $statsfile) or die "Copy failed: $!";
+
+# Start the server
+$node->start;
+
+is(exists_stat('database', $dboid, 0), 't', "Check that db stat exists.");
+is(exists_stat('function', $dboid, $funcoid),
+	't', "Check that function stat exists.");
+is(exists_stat('relation', $dboid, $tableoid),
+	't', "Check that relation stat exists.");
+
+# Fast shutdown
+$node->stop('immediate');
+
+ok(!-f "$og_stats", "No stats file should exist after immediate shutdown.");
+
+# Copy the old stats back to test we discard stats after crash restart
+copy($statsfile, $og_stats) or die "Copy failed: $!";
+
+# Start the server
+$node->start;
+
+# Stats should have been discarded
+is(exists_stat('database', $dboid, 0),
+	'f', "Check that db stat does not exist.");
+is(exists_stat('function', $dboid, $funcoid),
+	'f', "Check that function stat does not exist.");
+is(exists_stat('relation', $dboid, $tableoid),
+	'f', "Check that relation stat does not exist.");
+
+# Get rid of backup statsfile
+unlink $statsfile or die "cannot unlink $statsfile $!";
+
+
+# generate new stats and flush them
+trigger_funcrel_stat();
+
+is(exists_stat('database', $dboid, 0), 't', "Check that db stat exists.");
+is(exists_stat('function', $dboid, $funcoid),
+	't', "Check that function stat exists.");
+is(exists_stat('relation', $dboid, $tableoid),
+	't', "Check that relation stat exists.");
+
+# Regular shutdown
+$node->stop();
+
+sub overwrite_file
+{
+	my ($filename, $str) = @_;
+	open my $fh, ">", $filename
+	  or die "could not write \"$filename\": $!";
+	print $fh $str;
+	close $fh;
+	return;
+}
+
+overwrite_file($og_stats, "ZZZZZZZZZZZZZ");
+
+# Normal startup and no issues despite invalid stats file
+$node->start;
+
+# No stats present due to invalid stats file
+is(exists_stat('database', $dboid, 0),
+	'f', "Check that db stat does not exist.");
+is(exists_stat('function', $dboid, $funcoid),
+	'f', "Check that function stat does not exist.");
+is(exists_stat('relation', $dboid, $tableoid),
+	'f', "Check that relation stat does not exist.");
+
+
+## Checks related to stats persistency around restarts and resets
+
+# Ensure enough checkpoints to protect against races for test after reset,
+# even on very slow machines.
+$node->safe_psql($connect_db, "CHECKPOINT; CHECKPOINT;");
+
+
+## check checkpoint and wal stats are incremented due to restart
+
+my $ckpt_start = checkpoint_stats();
+my $wal_start  = wal_stats();
+$node->restart;
+
+my $sect         = "post restart";
+my $ckpt_restart = checkpoint_stats();
+my $wal_restart  = wal_stats();
+
+cmp_ok(
+	$ckpt_start->{count}, '<',
+	$ckpt_restart->{count},
+	"$sect: increased checkpoint count");
+cmp_ok(
+	$wal_start->{records}, '<',
+	$wal_restart->{records},
+	"$sect: increased wal record count");
+cmp_ok($wal_start->{bytes}, '<', $wal_restart->{bytes},
+	"$sect: increased wal bytes");
+is( $ckpt_start->{reset},
+	$ckpt_restart->{reset},
+	"$sect: checkpoint stats_reset equal");
+is($wal_start->{reset}, $wal_restart->{reset},
+	"$sect: wal stats_reset equal");
+
+
+## Check that checkpoint stats are reset, WAL stats aren't affected
+
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+
+$sect = "post ckpt reset";
+my $ckpt_reset     = checkpoint_stats();
+my $wal_ckpt_reset = wal_stats();
+
+cmp_ok($ckpt_restart->{count},
+	'>', $ckpt_reset->{count}, "$sect: checkpoint count smaller");
+cmp_ok($ckpt_start->{reset}, 'lt', $ckpt_reset->{reset},
+	"$sect: stats_reset newer");
+
+cmp_ok(
+	$wal_restart->{records},
+	'<=',
+	$wal_ckpt_reset->{records},
+	"$sect: wal record count not affected by reset");
+is( $wal_start->{reset},
+	$wal_ckpt_reset->{reset},
+	"$sect: wal stats_reset equal");
+
+
+## check that checkpoint stats stay reset after restart
+
+$node->restart;
+
+$sect = "post ckpt reset & restart";
+my $ckpt_restart_reset = checkpoint_stats();
+my $wal_restart2       = wal_stats();
+
+# made sure above there's enough checkpoints that this will be stable even on slow machines
+cmp_ok(
+	$ckpt_restart_reset->{count},
+	'<',
+	$ckpt_restart->{count},
+	"$sect: checkpoint still reset");
+is($ckpt_restart_reset->{reset},
+	$ckpt_reset->{reset}, "$sect: stats_reset same");
+
+cmp_ok(
+	$wal_ckpt_reset->{records},
+	'<',
+	$wal_restart2->{records},
+	"$sect: increased wal record count");
+cmp_ok(
+	$wal_ckpt_reset->{bytes},
+	'<',
+	$wal_restart2->{bytes},
+	"$sect: increased wal bytes");
+is( $wal_start->{reset},
+	$wal_restart2->{reset},
+	"$sect: wal stats_reset equal");
+
+
+## check WAL stats stay reset
+
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('wal')");
+
+$sect = "post wal reset";
+my $wal_reset = wal_stats();
+
+cmp_ok(
+	$wal_reset->{records}, '<',
+	$wal_restart2->{records},
+	"$sect: smaller record count");
+cmp_ok(
+	$wal_reset->{bytes}, '<',
+	$wal_restart2->{bytes},
+	"$sect: smaller bytes");
+cmp_ok(
+	$wal_reset->{reset}, 'gt',
+	$wal_restart2->{reset},
+	"$sect: newer stats_reset");
+
+$node->restart;
+
+$sect = "post wal reset & restart";
+my $wal_reset_restart = wal_stats();
+
+# enough WAL generated during prior tests and initdb to make this not racy
+cmp_ok(
+	$wal_reset_restart->{records},
+	'<',
+	$wal_restart2->{records},
+	"$sect: smaller record count");
+cmp_ok(
+	$wal_reset->{bytes}, '<',
+	$wal_restart2->{bytes},
+	"$sect: smaller bytes");
+cmp_ok(
+	$wal_reset->{reset}, 'gt',
+	$wal_restart2->{reset},
+	"$sect: newer stats_reset");
+
+
+$node->stop;
+done_testing();
+
+sub trigger_funcrel_stat
+{
+	$node->safe_psql(
+		$db_under_test, q[
+	SELECT * FROM tab_stats_crash_discard_test1;
+	SELECT func_stats_crash_discard1();
+    SELECT pg_stat_force_next_flush();]);
+}
+
+sub exists_stat
+{
+	my ($kind, $dboid, $objoid) = @_;
+
+	return $node->safe_psql($connect_db,
+		"SELECT pg_stat_exists_stat('$kind', $dboid, $objoid)");
+}
+
+sub checkpoint_stats
+{
+	my %results;
+
+	$results{count} = $node->safe_psql($connect_db,
+		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+	$results{reset} = $node->safe_psql($connect_db,
+		"SELECT stats_reset FROM pg_stat_bgwriter");
+
+	return \%results;
+}
+
+sub wal_stats
+{
+	my %results;
+	$results{records} =
+	  $node->safe_psql($connect_db, "SELECT wal_records FROM pg_stat_wal");
+	$results{bytes} =
+	  $node->safe_psql($connect_db, "SELECT wal_bytes FROM pg_stat_wal");
+	$results{reset} =
+	  $node->safe_psql($connect_db, "SELECT stats_reset FROM pg_stat_wal");
+
+	return \%results;
+}
-- 
2.35.1.677.gabf474a5dd


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



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

* [PATCH v69 16/28] pgstat: test: stats handling of restarts, including crashes.
@ 2022-03-20 20:33  Melanie Plageman <[email protected]>
  0 siblings, 0 replies; 4+ messages in thread

From: Melanie Plageman @ 2022-03-20 20:33 UTC (permalink / raw)

Stats should not be restored if the db crashed. Also, ensure invalid stats
files are handled gracefully.

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

diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
new file mode 100644
index 00000000000..55534b3a68d
--- /dev/null
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -0,0 +1,305 @@
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# Tests statistics handling around restarts, including handling of crashes and
+# invalid stats files, as well as restorting stats after "normal" restarts.
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+use File::Copy;
+
+my $node = PostgreSQL::Test::Cluster->new('primary');
+$node->init(allows_streaming => 1);
+$node->start;
+$node->append_conf('postgresql.conf', "track_functions = 'all'");
+$node->reload;
+
+my $connect_db    = 'postgres';
+my $db_under_test = 'test';
+
+$node->safe_psql($connect_db, "CREATE DATABASE $db_under_test");
+
+# Create table in test db
+$node->safe_psql($db_under_test,
+	"CREATE TABLE tab_stats_crash_discard_test1 AS SELECT generate_series(1,100) AS a"
+);
+
+# Create function in test db
+$node->safe_psql($db_under_test,
+	"CREATE FUNCTION func_stats_crash_discard1() RETURNS VOID AS 'select 2;' LANGUAGE SQL IMMUTABLE"
+);
+
+# collect object oids
+my $dboid = $node->safe_psql($db_under_test,
+	"SELECT oid FROM pg_database WHERE datname = '$db_under_test'");
+my $funcoid = $node->safe_psql($db_under_test,
+	"SELECT 'func_stats_crash_discard1()'::regprocedure::oid");
+my $tableoid = $node->safe_psql($db_under_test,
+	"SELECT 'tab_stats_crash_discard_test1'::regclass::oid");
+
+# generate stats and flush them
+trigger_funcrel_stat();
+
+# verify stats objects exist
+is(exists_stat('database', $dboid, 0), 't', "Check that db stat exists.");
+is(exists_stat('function', $dboid, $funcoid),
+	't', "Check that function stat exists.");
+is(exists_stat('relation', $dboid, $tableoid),
+	't', "Check that relation stat exists.");
+
+# Regular shutdown
+$node->stop();
+
+# Backup stats files
+my $statsfile = $PostgreSQL::Test::Utils::tmp_check . '/' . "discard_stats1";
+ok(!-f "$statsfile", "Backup statsfile cannot already exist");
+
+my $datadir  = $node->data_dir();
+my $og_stats = $datadir . '/' . "pg_stat" . '/' . "pgstat.stat";
+ok(-f "$og_stats", "Origin stats file must exist");
+copy($og_stats, $statsfile) or die "Copy failed: $!";
+
+# Start the server
+$node->start;
+
+is(exists_stat('database', $dboid, 0), 't', "Check that db stat exists.");
+is(exists_stat('function', $dboid, $funcoid),
+	't', "Check that function stat exists.");
+is(exists_stat('relation', $dboid, $tableoid),
+	't', "Check that relation stat exists.");
+
+# Fast shutdown
+$node->stop('immediate');
+
+ok(!-f "$og_stats", "No stats file should exist after immediate shutdown.");
+
+# Copy the old stats back to test we discard stats after crash restart
+copy($statsfile, $og_stats) or die "Copy failed: $!";
+
+# Start the server
+$node->start;
+
+# Stats should have been discarded
+is(exists_stat('database', $dboid, 0),
+	'f', "Check that db stat does not exist.");
+is(exists_stat('function', $dboid, $funcoid),
+	'f', "Check that function stat does not exist.");
+is(exists_stat('relation', $dboid, $tableoid),
+	'f', "Check that relation stat does not exist.");
+
+# Get rid of backup statsfile
+unlink $statsfile or die "cannot unlink $statsfile $!";
+
+
+# generate new stats and flush them
+trigger_funcrel_stat();
+
+is(exists_stat('database', $dboid, 0), 't', "Check that db stat exists.");
+is(exists_stat('function', $dboid, $funcoid),
+	't', "Check that function stat exists.");
+is(exists_stat('relation', $dboid, $tableoid),
+	't', "Check that relation stat exists.");
+
+# Regular shutdown
+$node->stop();
+
+sub overwrite_file
+{
+	my ($filename, $str) = @_;
+	open my $fh, ">", $filename
+	  or die "could not write \"$filename\": $!";
+	print $fh $str;
+	close $fh;
+	return;
+}
+
+overwrite_file($og_stats, "ZZZZZZZZZZZZZ");
+
+# Normal startup and no issues despite invalid stats file
+$node->start;
+
+# No stats present due to invalid stats file
+is(exists_stat('database', $dboid, 0),
+	'f', "Check that db stat does not exist.");
+is(exists_stat('function', $dboid, $funcoid),
+	'f', "Check that function stat does not exist.");
+is(exists_stat('relation', $dboid, $tableoid),
+	'f', "Check that relation stat does not exist.");
+
+
+## Checks related to stats persistency around restarts and resets
+
+# Ensure enough checkpoints to protect against races for test after reset,
+# even on very slow machines.
+$node->safe_psql($connect_db, "CHECKPOINT; CHECKPOINT;");
+
+
+## check checkpoint and wal stats are incremented due to restart
+
+my $ckpt_start = checkpoint_stats();
+my $wal_start  = wal_stats();
+$node->restart;
+
+my $sect         = "post restart";
+my $ckpt_restart = checkpoint_stats();
+my $wal_restart  = wal_stats();
+
+cmp_ok(
+	$ckpt_start->{count}, '<',
+	$ckpt_restart->{count},
+	"$sect: increased checkpoint count");
+cmp_ok(
+	$wal_start->{records}, '<',
+	$wal_restart->{records},
+	"$sect: increased wal record count");
+cmp_ok($wal_start->{bytes}, '<', $wal_restart->{bytes},
+	"$sect: increased wal bytes");
+is( $ckpt_start->{reset},
+	$ckpt_restart->{reset},
+	"$sect: checkpoint stats_reset equal");
+is($wal_start->{reset}, $wal_restart->{reset},
+	"$sect: wal stats_reset equal");
+
+
+## Check that checkpoint stats are reset, WAL stats aren't affected
+
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+
+$sect = "post ckpt reset";
+my $ckpt_reset     = checkpoint_stats();
+my $wal_ckpt_reset = wal_stats();
+
+cmp_ok($ckpt_restart->{count},
+	'>', $ckpt_reset->{count}, "$sect: checkpoint count smaller");
+cmp_ok($ckpt_start->{reset}, 'lt', $ckpt_reset->{reset},
+	"$sect: stats_reset newer");
+
+cmp_ok(
+	$wal_restart->{records},
+	'<=',
+	$wal_ckpt_reset->{records},
+	"$sect: wal record count not affected by reset");
+is( $wal_start->{reset},
+	$wal_ckpt_reset->{reset},
+	"$sect: wal stats_reset equal");
+
+
+## check that checkpoint stats stay reset after restart
+
+$node->restart;
+
+$sect = "post ckpt reset & restart";
+my $ckpt_restart_reset = checkpoint_stats();
+my $wal_restart2       = wal_stats();
+
+# made sure above there's enough checkpoints that this will be stable even on slow machines
+cmp_ok(
+	$ckpt_restart_reset->{count},
+	'<',
+	$ckpt_restart->{count},
+	"$sect: checkpoint still reset");
+is($ckpt_restart_reset->{reset},
+	$ckpt_reset->{reset}, "$sect: stats_reset same");
+
+cmp_ok(
+	$wal_ckpt_reset->{records},
+	'<',
+	$wal_restart2->{records},
+	"$sect: increased wal record count");
+cmp_ok(
+	$wal_ckpt_reset->{bytes},
+	'<',
+	$wal_restart2->{bytes},
+	"$sect: increased wal bytes");
+is( $wal_start->{reset},
+	$wal_restart2->{reset},
+	"$sect: wal stats_reset equal");
+
+
+## check WAL stats stay reset
+
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('wal')");
+
+$sect = "post wal reset";
+my $wal_reset = wal_stats();
+
+cmp_ok(
+	$wal_reset->{records}, '<',
+	$wal_restart2->{records},
+	"$sect: smaller record count");
+cmp_ok(
+	$wal_reset->{bytes}, '<',
+	$wal_restart2->{bytes},
+	"$sect: smaller bytes");
+cmp_ok(
+	$wal_reset->{reset}, 'gt',
+	$wal_restart2->{reset},
+	"$sect: newer stats_reset");
+
+$node->restart;
+
+$sect = "post wal reset & restart";
+my $wal_reset_restart = wal_stats();
+
+# enough WAL generated during prior tests and initdb to make this not racy
+cmp_ok(
+	$wal_reset_restart->{records},
+	'<',
+	$wal_restart2->{records},
+	"$sect: smaller record count");
+cmp_ok(
+	$wal_reset->{bytes}, '<',
+	$wal_restart2->{bytes},
+	"$sect: smaller bytes");
+cmp_ok(
+	$wal_reset->{reset}, 'gt',
+	$wal_restart2->{reset},
+	"$sect: newer stats_reset");
+
+
+$node->stop;
+done_testing();
+
+sub trigger_funcrel_stat
+{
+	$node->safe_psql(
+		$db_under_test, q[
+	SELECT * FROM tab_stats_crash_discard_test1;
+	SELECT func_stats_crash_discard1();
+    SELECT pg_stat_force_next_flush();]);
+}
+
+sub exists_stat
+{
+	my ($kind, $dboid, $objoid) = @_;
+
+	return $node->safe_psql($connect_db,
+		"SELECT pg_stat_exists_stat('$kind', $dboid, $objoid)");
+}
+
+sub checkpoint_stats
+{
+	my %results;
+
+	$results{count} = $node->safe_psql($connect_db,
+		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+	$results{reset} = $node->safe_psql($connect_db,
+		"SELECT stats_reset FROM pg_stat_bgwriter");
+
+	return \%results;
+}
+
+sub wal_stats
+{
+	my %results;
+	$results{records} =
+	  $node->safe_psql($connect_db, "SELECT wal_records FROM pg_stat_wal");
+	$results{bytes} =
+	  $node->safe_psql($connect_db, "SELECT wal_bytes FROM pg_stat_wal");
+	$results{reset} =
+	  $node->safe_psql($connect_db, "SELECT stats_reset FROM pg_stat_wal");
+
+	return \%results;
+}
-- 
2.35.1.677.gabf474a5dd


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



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

* [PATCH v70 19/27] pgstat: test: stats handling of restarts, including crashes.
@ 2022-03-20 20:33  Melanie Plageman <[email protected]>
  0 siblings, 0 replies; 4+ messages in thread

From: Melanie Plageman @ 2022-03-20 20:33 UTC (permalink / raw)

Stats should not be restored if the db crashed. Also, ensure invalid stats
files are handled gracefully.

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

diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
new file mode 100644
index 00000000000..55534b3a68d
--- /dev/null
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -0,0 +1,305 @@
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# Tests statistics handling around restarts, including handling of crashes and
+# invalid stats files, as well as restorting stats after "normal" restarts.
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+use File::Copy;
+
+my $node = PostgreSQL::Test::Cluster->new('primary');
+$node->init(allows_streaming => 1);
+$node->start;
+$node->append_conf('postgresql.conf', "track_functions = 'all'");
+$node->reload;
+
+my $connect_db    = 'postgres';
+my $db_under_test = 'test';
+
+$node->safe_psql($connect_db, "CREATE DATABASE $db_under_test");
+
+# Create table in test db
+$node->safe_psql($db_under_test,
+	"CREATE TABLE tab_stats_crash_discard_test1 AS SELECT generate_series(1,100) AS a"
+);
+
+# Create function in test db
+$node->safe_psql($db_under_test,
+	"CREATE FUNCTION func_stats_crash_discard1() RETURNS VOID AS 'select 2;' LANGUAGE SQL IMMUTABLE"
+);
+
+# collect object oids
+my $dboid = $node->safe_psql($db_under_test,
+	"SELECT oid FROM pg_database WHERE datname = '$db_under_test'");
+my $funcoid = $node->safe_psql($db_under_test,
+	"SELECT 'func_stats_crash_discard1()'::regprocedure::oid");
+my $tableoid = $node->safe_psql($db_under_test,
+	"SELECT 'tab_stats_crash_discard_test1'::regclass::oid");
+
+# generate stats and flush them
+trigger_funcrel_stat();
+
+# verify stats objects exist
+is(exists_stat('database', $dboid, 0), 't', "Check that db stat exists.");
+is(exists_stat('function', $dboid, $funcoid),
+	't', "Check that function stat exists.");
+is(exists_stat('relation', $dboid, $tableoid),
+	't', "Check that relation stat exists.");
+
+# Regular shutdown
+$node->stop();
+
+# Backup stats files
+my $statsfile = $PostgreSQL::Test::Utils::tmp_check . '/' . "discard_stats1";
+ok(!-f "$statsfile", "Backup statsfile cannot already exist");
+
+my $datadir  = $node->data_dir();
+my $og_stats = $datadir . '/' . "pg_stat" . '/' . "pgstat.stat";
+ok(-f "$og_stats", "Origin stats file must exist");
+copy($og_stats, $statsfile) or die "Copy failed: $!";
+
+# Start the server
+$node->start;
+
+is(exists_stat('database', $dboid, 0), 't', "Check that db stat exists.");
+is(exists_stat('function', $dboid, $funcoid),
+	't', "Check that function stat exists.");
+is(exists_stat('relation', $dboid, $tableoid),
+	't', "Check that relation stat exists.");
+
+# Fast shutdown
+$node->stop('immediate');
+
+ok(!-f "$og_stats", "No stats file should exist after immediate shutdown.");
+
+# Copy the old stats back to test we discard stats after crash restart
+copy($statsfile, $og_stats) or die "Copy failed: $!";
+
+# Start the server
+$node->start;
+
+# Stats should have been discarded
+is(exists_stat('database', $dboid, 0),
+	'f', "Check that db stat does not exist.");
+is(exists_stat('function', $dboid, $funcoid),
+	'f', "Check that function stat does not exist.");
+is(exists_stat('relation', $dboid, $tableoid),
+	'f', "Check that relation stat does not exist.");
+
+# Get rid of backup statsfile
+unlink $statsfile or die "cannot unlink $statsfile $!";
+
+
+# generate new stats and flush them
+trigger_funcrel_stat();
+
+is(exists_stat('database', $dboid, 0), 't', "Check that db stat exists.");
+is(exists_stat('function', $dboid, $funcoid),
+	't', "Check that function stat exists.");
+is(exists_stat('relation', $dboid, $tableoid),
+	't', "Check that relation stat exists.");
+
+# Regular shutdown
+$node->stop();
+
+sub overwrite_file
+{
+	my ($filename, $str) = @_;
+	open my $fh, ">", $filename
+	  or die "could not write \"$filename\": $!";
+	print $fh $str;
+	close $fh;
+	return;
+}
+
+overwrite_file($og_stats, "ZZZZZZZZZZZZZ");
+
+# Normal startup and no issues despite invalid stats file
+$node->start;
+
+# No stats present due to invalid stats file
+is(exists_stat('database', $dboid, 0),
+	'f', "Check that db stat does not exist.");
+is(exists_stat('function', $dboid, $funcoid),
+	'f', "Check that function stat does not exist.");
+is(exists_stat('relation', $dboid, $tableoid),
+	'f', "Check that relation stat does not exist.");
+
+
+## Checks related to stats persistency around restarts and resets
+
+# Ensure enough checkpoints to protect against races for test after reset,
+# even on very slow machines.
+$node->safe_psql($connect_db, "CHECKPOINT; CHECKPOINT;");
+
+
+## check checkpoint and wal stats are incremented due to restart
+
+my $ckpt_start = checkpoint_stats();
+my $wal_start  = wal_stats();
+$node->restart;
+
+my $sect         = "post restart";
+my $ckpt_restart = checkpoint_stats();
+my $wal_restart  = wal_stats();
+
+cmp_ok(
+	$ckpt_start->{count}, '<',
+	$ckpt_restart->{count},
+	"$sect: increased checkpoint count");
+cmp_ok(
+	$wal_start->{records}, '<',
+	$wal_restart->{records},
+	"$sect: increased wal record count");
+cmp_ok($wal_start->{bytes}, '<', $wal_restart->{bytes},
+	"$sect: increased wal bytes");
+is( $ckpt_start->{reset},
+	$ckpt_restart->{reset},
+	"$sect: checkpoint stats_reset equal");
+is($wal_start->{reset}, $wal_restart->{reset},
+	"$sect: wal stats_reset equal");
+
+
+## Check that checkpoint stats are reset, WAL stats aren't affected
+
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+
+$sect = "post ckpt reset";
+my $ckpt_reset     = checkpoint_stats();
+my $wal_ckpt_reset = wal_stats();
+
+cmp_ok($ckpt_restart->{count},
+	'>', $ckpt_reset->{count}, "$sect: checkpoint count smaller");
+cmp_ok($ckpt_start->{reset}, 'lt', $ckpt_reset->{reset},
+	"$sect: stats_reset newer");
+
+cmp_ok(
+	$wal_restart->{records},
+	'<=',
+	$wal_ckpt_reset->{records},
+	"$sect: wal record count not affected by reset");
+is( $wal_start->{reset},
+	$wal_ckpt_reset->{reset},
+	"$sect: wal stats_reset equal");
+
+
+## check that checkpoint stats stay reset after restart
+
+$node->restart;
+
+$sect = "post ckpt reset & restart";
+my $ckpt_restart_reset = checkpoint_stats();
+my $wal_restart2       = wal_stats();
+
+# made sure above there's enough checkpoints that this will be stable even on slow machines
+cmp_ok(
+	$ckpt_restart_reset->{count},
+	'<',
+	$ckpt_restart->{count},
+	"$sect: checkpoint still reset");
+is($ckpt_restart_reset->{reset},
+	$ckpt_reset->{reset}, "$sect: stats_reset same");
+
+cmp_ok(
+	$wal_ckpt_reset->{records},
+	'<',
+	$wal_restart2->{records},
+	"$sect: increased wal record count");
+cmp_ok(
+	$wal_ckpt_reset->{bytes},
+	'<',
+	$wal_restart2->{bytes},
+	"$sect: increased wal bytes");
+is( $wal_start->{reset},
+	$wal_restart2->{reset},
+	"$sect: wal stats_reset equal");
+
+
+## check WAL stats stay reset
+
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('wal')");
+
+$sect = "post wal reset";
+my $wal_reset = wal_stats();
+
+cmp_ok(
+	$wal_reset->{records}, '<',
+	$wal_restart2->{records},
+	"$sect: smaller record count");
+cmp_ok(
+	$wal_reset->{bytes}, '<',
+	$wal_restart2->{bytes},
+	"$sect: smaller bytes");
+cmp_ok(
+	$wal_reset->{reset}, 'gt',
+	$wal_restart2->{reset},
+	"$sect: newer stats_reset");
+
+$node->restart;
+
+$sect = "post wal reset & restart";
+my $wal_reset_restart = wal_stats();
+
+# enough WAL generated during prior tests and initdb to make this not racy
+cmp_ok(
+	$wal_reset_restart->{records},
+	'<',
+	$wal_restart2->{records},
+	"$sect: smaller record count");
+cmp_ok(
+	$wal_reset->{bytes}, '<',
+	$wal_restart2->{bytes},
+	"$sect: smaller bytes");
+cmp_ok(
+	$wal_reset->{reset}, 'gt',
+	$wal_restart2->{reset},
+	"$sect: newer stats_reset");
+
+
+$node->stop;
+done_testing();
+
+sub trigger_funcrel_stat
+{
+	$node->safe_psql(
+		$db_under_test, q[
+	SELECT * FROM tab_stats_crash_discard_test1;
+	SELECT func_stats_crash_discard1();
+    SELECT pg_stat_force_next_flush();]);
+}
+
+sub exists_stat
+{
+	my ($kind, $dboid, $objoid) = @_;
+
+	return $node->safe_psql($connect_db,
+		"SELECT pg_stat_exists_stat('$kind', $dboid, $objoid)");
+}
+
+sub checkpoint_stats
+{
+	my %results;
+
+	$results{count} = $node->safe_psql($connect_db,
+		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+	$results{reset} = $node->safe_psql($connect_db,
+		"SELECT stats_reset FROM pg_stat_bgwriter");
+
+	return \%results;
+}
+
+sub wal_stats
+{
+	my %results;
+	$results{records} =
+	  $node->safe_psql($connect_db, "SELECT wal_records FROM pg_stat_wal");
+	$results{bytes} =
+	  $node->safe_psql($connect_db, "SELECT wal_bytes FROM pg_stat_wal");
+	$results{reset} =
+	  $node->safe_psql($connect_db, "SELECT stats_reset FROM pg_stat_wal");
+
+	return \%results;
+}
-- 
2.35.1.677.gabf474a5dd


--vl7on5vfmrsyxmos
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v70-0020-pgstat-test-test-stats-interactions-with-streami.patch"



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


end of thread, other threads:[~2022-03-20 20:33 UTC | newest]

Thread overview: 4+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2019-12-11 12:54 [PATCH v25 4/5] Add ALTER INDEX ... ALTER COLLATION ... REFRESH VERSION. Julien Rouhaud <[email protected]>
2022-03-20 20:33 [PATCH v70 19/27] pgstat: test: stats handling of restarts, including crashes. Melanie Plageman <[email protected]>
2022-03-20 20:33 [PATCH v68 20/31] pgstat: test: stats handling of restarts, including crashes. Melanie Plageman <[email protected]>
2022-03-20 20:33 [PATCH v69 16/28] pgstat: test: stats handling of restarts, including crashes. Melanie Plageman <[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