Skip to content

Commit 53b9cd2

Browse files
committed
pgstat: test stats interactions with physical replication.
Tests that standbys: - drop stats for objects when the those records are replayed - persist stats across graceful restarts - discard stats after immediate / crash restarts Author: Melanie Plageman <melanieplageman@gmail.com> Author: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/20220303021600.hs34ghqcw6zcokdh@alap3.anarazel.de
1 parent a90641e commit 53b9cd2

File tree

1 file changed

+206
-0
lines changed

1 file changed

+206
-0
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# Copyright (c) 2021-2022, PostgreSQL Global Development Group
2+
3+
# Tests that standbys:
4+
# - drop stats for objects when the those records are replayed
5+
# - persist stats across graceful restarts
6+
# - discard stats after immediate / crash restarts
7+
8+
use strict;
9+
use warnings;
10+
use PostgreSQL::Test::Cluster;
11+
use PostgreSQL::Test::Utils;
12+
use Test::More;
13+
14+
my $node_primary = PostgreSQL::Test::Cluster->new('primary');
15+
$node_primary->init(allows_streaming => 1);
16+
$node_primary->append_conf('postgresql.conf', "track_functions = 'all'");
17+
$node_primary->start;
18+
19+
my $backup_name = 'my_backup';
20+
$node_primary->backup($backup_name);
21+
22+
my $node_standby = PostgreSQL::Test::Cluster->new('standby');
23+
$node_standby->init_from_backup($node_primary, $backup_name,
24+
has_streaming => 1);
25+
$node_standby->start;
26+
27+
28+
## Test that stats are cleaned up on standby after dropping table or function
29+
30+
my $sect = 'initial';
31+
32+
my ($dboid, $tableoid, $funcoid) =
33+
populate_standby_stats('postgres', 'public');
34+
test_standby_func_tab_stats_status('postgres',
35+
$dboid, $tableoid, $funcoid, 't');
36+
37+
drop_table_by_oid('postgres', $tableoid);
38+
drop_function_by_oid('postgres', $funcoid);
39+
40+
$sect = 'post drop';
41+
my $primary_lsn = $node_primary->lsn('flush');
42+
$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
43+
test_standby_func_tab_stats_status('postgres',
44+
$dboid, $tableoid, $funcoid, 'f');
45+
46+
47+
## Test that stats are cleaned up on standby after dropping indirectly
48+
49+
$sect = "schema creation";
50+
51+
$node_primary->safe_psql('postgres', "CREATE SCHEMA drop_schema_test1");
52+
$primary_lsn = $node_primary->lsn('flush');
53+
$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
54+
55+
($dboid, $tableoid, $funcoid) =
56+
populate_standby_stats('postgres', 'drop_schema_test1');
57+
58+
test_standby_func_tab_stats_status('postgres',
59+
$dboid, $tableoid, $funcoid, 't');
60+
$node_primary->safe_psql('postgres', "DROP SCHEMA drop_schema_test1 CASCADE");
61+
62+
$sect = "post schema drop";
63+
64+
$primary_lsn = $node_primary->lsn('flush');
65+
$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
66+
67+
# verify table and function stats removed from standby
68+
test_standby_func_tab_stats_status('postgres',
69+
$dboid, $tableoid, $funcoid, 'f');
70+
71+
72+
## Test that stats are cleaned up on standby after dropping database
73+
74+
$sect = "createdb";
75+
76+
$node_primary->safe_psql('postgres', "CREATE DATABASE test");
77+
$primary_lsn = $node_primary->lsn('flush');
78+
$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
79+
80+
($dboid, $tableoid, $funcoid) = populate_standby_stats('test', 'public');
81+
82+
# verify stats are present
83+
test_standby_func_tab_stats_status('test', $dboid, $tableoid, $funcoid, 't');
84+
test_standby_db_stats_status('test', $dboid, 't');
85+
86+
$node_primary->safe_psql('postgres', "DROP DATABASE test");
87+
$sect = "post dropdb";
88+
$primary_lsn = $node_primary->lsn('flush');
89+
$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
90+
91+
# Test that the stats were cleaned up on standby
92+
# Note that this connects to 'postgres' but provides the dboid of dropped db
93+
# 'test' which we acquired previously
94+
test_standby_func_tab_stats_status('postgres',
95+
$dboid, $tableoid, $funcoid, 'f');
96+
97+
test_standby_db_stats_status('postgres', $dboid, 'f');
98+
99+
100+
## verify that stats persist across graceful restarts on a replica
101+
102+
# NB: Can't test database stats, they're immediately repopulated when
103+
# reconnecting...
104+
$sect = "pre restart";
105+
($dboid, $tableoid, $funcoid) = populate_standby_stats('postgres', 'public');
106+
test_standby_func_tab_stats_status('postgres',
107+
$dboid, $tableoid, $funcoid, 't');
108+
109+
$node_standby->restart();
110+
111+
$sect = "post non-immediate";
112+
113+
test_standby_func_tab_stats_status('postgres',
114+
$dboid, $tableoid, $funcoid, 't');
115+
116+
# but gone after an immediate restart
117+
$node_standby->stop('immediate');
118+
$node_standby->start();
119+
120+
$sect = "post immediate restart";
121+
122+
test_standby_func_tab_stats_status('postgres',
123+
$dboid, $tableoid, $funcoid, 'f');
124+
125+
126+
done_testing();
127+
128+
129+
sub populate_standby_stats
130+
{
131+
my ($connect_db, $schema) = @_;
132+
133+
# create objects on primary
134+
$node_primary->safe_psql($connect_db,
135+
"CREATE TABLE $schema.drop_tab_test1 AS SELECT generate_series(1,100) AS a"
136+
);
137+
$node_primary->safe_psql($connect_db,
138+
"CREATE FUNCTION $schema.drop_func_test1() RETURNS VOID AS 'select 2;' LANGUAGE SQL IMMUTABLE"
139+
);
140+
my $primary_lsn = $node_primary->lsn('flush');
141+
$node_primary->wait_for_catchup($node_standby, 'replay', $primary_lsn);
142+
143+
# collect object oids
144+
my $dboid = $node_standby->safe_psql($connect_db,
145+
"SELECT oid FROM pg_database WHERE datname = '$connect_db'");
146+
my $tableoid = $node_standby->safe_psql($connect_db,
147+
"SELECT '$schema.drop_tab_test1'::regclass::oid");
148+
my $funcoid = $node_standby->safe_psql($connect_db,
149+
"SELECT '$schema.drop_func_test1()'::regprocedure::oid");
150+
151+
# generate stats on standby
152+
$node_standby->safe_psql($connect_db,
153+
"SELECT * FROM $schema.drop_tab_test1");
154+
$node_standby->safe_psql($connect_db, "SELECT $schema.drop_func_test1()");
155+
156+
return ($dboid, $tableoid, $funcoid);
157+
}
158+
159+
sub drop_function_by_oid
160+
{
161+
my ($connect_db, $funcoid) = @_;
162+
163+
# Get function name from returned oid
164+
my $func_name = $node_primary->safe_psql($connect_db,
165+
"SELECT '$funcoid'::regprocedure");
166+
$node_primary->safe_psql($connect_db, "DROP FUNCTION $func_name");
167+
}
168+
169+
sub drop_table_by_oid
170+
{
171+
my ($connect_db, $tableoid) = @_;
172+
173+
# Get table name from returned oid
174+
my $table_name =
175+
$node_primary->safe_psql($connect_db, "SELECT '$tableoid'::regclass");
176+
$node_primary->safe_psql($connect_db, "DROP TABLE $table_name");
177+
}
178+
179+
sub test_standby_func_tab_stats_status
180+
{
181+
local $Test::Builder::Level = $Test::Builder::Level + 1;
182+
my ($connect_db, $dboid, $tableoid, $funcoid, $present) = @_;
183+
184+
my %expected = (rel => $present, func => $present);
185+
my %stats;
186+
187+
$stats{rel} = $node_standby->safe_psql($connect_db,
188+
"SELECT pg_stat_have_stats('relation', $dboid, $tableoid)");
189+
$stats{func} = $node_standby->safe_psql($connect_db,
190+
"SELECT pg_stat_have_stats('function', $dboid, $funcoid)");
191+
192+
is_deeply(\%stats, \%expected, "$sect: standby stats as expected");
193+
194+
return;
195+
}
196+
197+
sub test_standby_db_stats_status
198+
{
199+
local $Test::Builder::Level = $Test::Builder::Level + 1;
200+
my ($connect_db, $dboid, $present) = @_;
201+
202+
is( $node_standby->safe_psql(
203+
$connect_db, "SELECT pg_stat_have_stats('database', $dboid, 0)"),
204+
$present,
205+
"$sect: standby db stats as expected");
206+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy