Update copyright for 2022
[pgsql.git] / src / test / recovery / t / 007_sync_rep.pl
blobcebd59011131c3c8b6d9173c774652bb148a2ef1
2 # Copyright (c) 2021-2022, PostgreSQL Global Development Group
4 # Minimal test testing synchronous replication sync_state transition
5 use strict;
6 use warnings;
7 use PostgreSQL::Test::Cluster;
8 use PostgreSQL::Test::Utils;
9 use Test::More tests => 11;
11 # Query checking sync_priority and sync_state of each standby
12 my $check_sql =
13 "SELECT application_name, sync_priority, sync_state FROM pg_stat_replication ORDER BY application_name;";
15 # Check that sync_state of each standby is expected (waiting till it is).
16 # If $setting is given, synchronous_standby_names is set to it and
17 # the configuration file is reloaded before the test.
18 sub test_sync_state
20 local $Test::Builder::Level = $Test::Builder::Level + 1;
22 my ($self, $expected, $msg, $setting) = @_;
24 if (defined($setting))
26 $self->safe_psql('postgres',
27 "ALTER SYSTEM SET synchronous_standby_names = '$setting';");
28 $self->reload;
31 ok($self->poll_query_until('postgres', $check_sql, $expected), $msg);
32 return;
35 # Start a standby and check that it is registered within the WAL sender
36 # array of the given primary. This polls the primary's pg_stat_replication
37 # until the standby is confirmed as registered.
38 sub start_standby_and_wait
40 my ($primary, $standby) = @_;
41 my $primary_name = $primary->name;
42 my $standby_name = $standby->name;
43 my $query =
44 "SELECT count(1) = 1 FROM pg_stat_replication WHERE application_name = '$standby_name'";
46 $standby->start;
48 print("### Waiting for standby \"$standby_name\" on \"$primary_name\"\n");
49 $primary->poll_query_until('postgres', $query);
50 return;
53 # Initialize primary node
54 my $node_primary = PostgreSQL::Test::Cluster->new('primary');
55 $node_primary->init(allows_streaming => 1);
56 $node_primary->start;
57 my $backup_name = 'primary_backup';
59 # Take backup
60 $node_primary->backup($backup_name);
62 # Create all the standbys. Their status on the primary is checked to ensure
63 # the ordering of each one of them in the WAL sender array of the primary.
65 # Create standby1 linking to primary
66 my $node_standby_1 = PostgreSQL::Test::Cluster->new('standby1');
67 $node_standby_1->init_from_backup($node_primary, $backup_name,
68 has_streaming => 1);
69 start_standby_and_wait($node_primary, $node_standby_1);
71 # Create standby2 linking to primary
72 my $node_standby_2 = PostgreSQL::Test::Cluster->new('standby2');
73 $node_standby_2->init_from_backup($node_primary, $backup_name,
74 has_streaming => 1);
75 start_standby_and_wait($node_primary, $node_standby_2);
77 # Create standby3 linking to primary
78 my $node_standby_3 = PostgreSQL::Test::Cluster->new('standby3');
79 $node_standby_3->init_from_backup($node_primary, $backup_name,
80 has_streaming => 1);
81 start_standby_and_wait($node_primary, $node_standby_3);
83 # Check that sync_state is determined correctly when
84 # synchronous_standby_names is specified in old syntax.
85 test_sync_state(
86 $node_primary, qq(standby1|1|sync
87 standby2|2|potential
88 standby3|0|async),
89 'old syntax of synchronous_standby_names',
90 'standby1,standby2');
92 # Check that all the standbys are considered as either sync or
93 # potential when * is specified in synchronous_standby_names.
94 # Note that standby1 is chosen as sync standby because
95 # it's stored in the head of WalSnd array which manages
96 # all the standbys though they have the same priority.
97 test_sync_state(
98 $node_primary, qq(standby1|1|sync
99 standby2|1|potential
100 standby3|1|potential),
101 'asterisk in synchronous_standby_names',
102 '*');
104 # Stop and start standbys to rearrange the order of standbys
105 # in WalSnd array. Now, if standbys have the same priority,
106 # standby2 is selected preferentially and standby3 is next.
107 $node_standby_1->stop;
108 $node_standby_2->stop;
109 $node_standby_3->stop;
111 # Make sure that each standby reports back to the primary in the wanted
112 # order.
113 start_standby_and_wait($node_primary, $node_standby_2);
114 start_standby_and_wait($node_primary, $node_standby_3);
116 # Specify 2 as the number of sync standbys.
117 # Check that two standbys are in 'sync' state.
118 test_sync_state(
119 $node_primary, qq(standby2|2|sync
120 standby3|3|sync),
121 '2 synchronous standbys',
122 '2(standby1,standby2,standby3)');
124 # Start standby1
125 start_standby_and_wait($node_primary, $node_standby_1);
127 # Create standby4 linking to primary
128 my $node_standby_4 = PostgreSQL::Test::Cluster->new('standby4');
129 $node_standby_4->init_from_backup($node_primary, $backup_name,
130 has_streaming => 1);
131 $node_standby_4->start;
133 # Check that standby1 and standby2 whose names appear earlier in
134 # synchronous_standby_names are considered as sync. Also check that
135 # standby3 appearing later represents potential, and standby4 is
136 # in 'async' state because it's not in the list.
137 test_sync_state(
138 $node_primary, qq(standby1|1|sync
139 standby2|2|sync
140 standby3|3|potential
141 standby4|0|async),
142 '2 sync, 1 potential, and 1 async');
144 # Check that sync_state of each standby is determined correctly
145 # when num_sync exceeds the number of names of potential sync standbys
146 # specified in synchronous_standby_names.
147 test_sync_state(
148 $node_primary, qq(standby1|0|async
149 standby2|4|sync
150 standby3|3|sync
151 standby4|1|sync),
152 'num_sync exceeds the num of potential sync standbys',
153 '6(standby4,standby0,standby3,standby2)');
155 # The setting that * comes before another standby name is acceptable
156 # but does not make sense in most cases. Check that sync_state is
157 # chosen properly even in case of that setting. standby1 is selected
158 # as synchronous as it has the highest priority, and is followed by a
159 # second standby listed first in the WAL sender array, which is
160 # standby2 in this case.
161 test_sync_state(
162 $node_primary, qq(standby1|1|sync
163 standby2|2|sync
164 standby3|2|potential
165 standby4|2|potential),
166 'asterisk before another standby name',
167 '2(standby1,*,standby2)');
169 # Check that the setting of '2(*)' chooses standby2 and standby3 that are stored
170 # earlier in WalSnd array as sync standbys.
171 test_sync_state(
172 $node_primary, qq(standby1|1|potential
173 standby2|1|sync
174 standby3|1|sync
175 standby4|1|potential),
176 'multiple standbys having the same priority are chosen as sync',
177 '2(*)');
179 # Stop Standby3 which is considered in 'sync' state.
180 $node_standby_3->stop;
182 # Check that the state of standby1 stored earlier in WalSnd array than
183 # standby4 is transited from potential to sync.
184 test_sync_state(
185 $node_primary, qq(standby1|1|sync
186 standby2|1|sync
187 standby4|1|potential),
188 'potential standby found earlier in array is promoted to sync');
190 # Check that standby1 and standby2 are chosen as sync standbys
191 # based on their priorities.
192 test_sync_state(
193 $node_primary, qq(standby1|1|sync
194 standby2|2|sync
195 standby4|0|async),
196 'priority-based sync replication specified by FIRST keyword',
197 'FIRST 2(standby1, standby2)');
199 # Check that all the listed standbys are considered as candidates
200 # for sync standbys in a quorum-based sync replication.
201 test_sync_state(
202 $node_primary, qq(standby1|1|quorum
203 standby2|1|quorum
204 standby4|0|async),
205 '2 quorum and 1 async',
206 'ANY 2(standby1, standby2)');
208 # Start Standby3 which will be considered in 'quorum' state.
209 $node_standby_3->start;
211 # Check that the setting of 'ANY 2(*)' chooses all standbys as
212 # candidates for quorum sync standbys.
213 test_sync_state(
214 $node_primary, qq(standby1|1|quorum
215 standby2|1|quorum
216 standby3|1|quorum
217 standby4|1|quorum),
218 'all standbys are considered as candidates for quorum sync standbys',
219 'ANY 2(*)');