Update copyright for 2022
[pgsql.git] / src / test / recovery / t / 020_archive_status.pl
blob06c2b69ef40cf7d7122014d5fb25024a79e1c890
2 # Copyright (c) 2021-2022, PostgreSQL Global Development Group
5 # Tests related to WAL archiving and recovery.
7 use strict;
8 use warnings;
9 use PostgreSQL::Test::Cluster;
10 use PostgreSQL::Test::Utils;
11 use Test::More tests => 16;
12 use Config;
14 my $primary = PostgreSQL::Test::Cluster->new('primary');
15 $primary->init(
16 has_archiving => 1,
17 allows_streaming => 1);
18 $primary->append_conf('postgresql.conf', 'autovacuum = off');
19 $primary->start;
20 my $primary_data = $primary->data_dir;
22 # Temporarily use an archive_command value to make the archiver fail,
23 # knowing that archiving is enabled. Note that we cannot use a command
24 # that does not exist as in this case the archiver process would just exit
25 # without reporting the failure to pg_stat_archiver. This also cannot
26 # use a plain "false" as that's unportable on Windows. So, instead, as
27 # a portable solution, use an archive command based on a command known to
28 # work but will fail: copy with an incorrect original path.
29 my $incorrect_command =
30 $PostgreSQL::Test::Utils::windows_os
31 ? qq{copy "%p_does_not_exist" "%f_does_not_exist"}
32 : qq{cp "%p_does_not_exist" "%f_does_not_exist"};
33 $primary->safe_psql(
34 'postgres', qq{
35 ALTER SYSTEM SET archive_command TO '$incorrect_command';
36 SELECT pg_reload_conf();
37 });
39 # Save the WAL segment currently in use and switch to a new segment.
40 # This will be used to track the activity of the archiver.
41 my $segment_name_1 = $primary->safe_psql('postgres',
42 q{SELECT pg_walfile_name(pg_current_wal_lsn())});
43 my $segment_path_1 = "pg_wal/archive_status/$segment_name_1";
44 my $segment_path_1_ready = "$segment_path_1.ready";
45 my $segment_path_1_done = "$segment_path_1.done";
46 $primary->safe_psql(
47 'postgres', q{
48 CREATE TABLE mine AS SELECT generate_series(1,10) AS x;
49 SELECT pg_switch_wal();
50 CHECKPOINT;
51 });
53 # Wait for an archive failure.
54 $primary->poll_query_until('postgres',
55 q{SELECT failed_count > 0 FROM pg_stat_archiver}, 't')
56 or die "Timed out while waiting for archiving to fail";
57 ok( -f "$primary_data/$segment_path_1_ready",
58 ".ready file exists for WAL segment $segment_name_1 waiting to be archived"
60 ok( !-f "$primary_data/$segment_path_1_done",
61 ".done file does not exist for WAL segment $segment_name_1 waiting to be archived"
64 is( $primary->safe_psql(
65 'postgres', q{
66 SELECT archived_count, last_failed_wal
67 FROM pg_stat_archiver
68 }),
69 "0|$segment_name_1",
70 "pg_stat_archiver failed to archive $segment_name_1");
72 # Crash the cluster for the next test in charge of checking that non-archived
73 # WAL segments are not removed.
74 $primary->stop('immediate');
76 # Recovery tests for the archiving with a standby partially check
77 # the recovery behavior when restoring a backup taken using a
78 # snapshot with no pg_start/stop_backup. In this situation,
79 # the recovered standby should enter first crash recovery then
80 # switch to regular archive recovery. Note that the base backup
81 # is taken here so as archive_command will fail. This is necessary
82 # for the assumptions of the tests done with the standbys below.
83 $primary->backup_fs_cold('backup');
85 $primary->start;
86 ok( -f "$primary_data/$segment_path_1_ready",
87 ".ready file for WAL segment $segment_name_1 still exists after crash recovery on primary"
90 # Allow WAL archiving again and wait for a success.
91 $primary->safe_psql(
92 'postgres', q{
93 ALTER SYSTEM RESET archive_command;
94 SELECT pg_reload_conf();
95 });
97 $primary->poll_query_until('postgres',
98 q{SELECT archived_count FROM pg_stat_archiver}, '1')
99 or die "Timed out while waiting for archiving to finish";
101 ok(!-f "$primary_data/$segment_path_1_ready",
102 ".ready file for archived WAL segment $segment_name_1 removed");
104 ok(-f "$primary_data/$segment_path_1_done",
105 ".done file for archived WAL segment $segment_name_1 exists");
107 is( $primary->safe_psql(
108 'postgres', q{ SELECT last_archived_wal FROM pg_stat_archiver }),
109 $segment_name_1,
110 "archive success reported in pg_stat_archiver for WAL segment $segment_name_1"
113 # Create some WAL activity and a new checkpoint so as the next standby can
114 # create a restartpoint. As this standby starts in crash recovery because
115 # of the cold backup taken previously, it needs a clean restartpoint to deal
116 # with existing status files.
117 my $segment_name_2 = $primary->safe_psql('postgres',
118 q{SELECT pg_walfile_name(pg_current_wal_lsn())});
119 my $segment_path_2 = "pg_wal/archive_status/$segment_name_2";
120 my $segment_path_2_ready = "$segment_path_2.ready";
121 my $segment_path_2_done = "$segment_path_2.done";
122 $primary->safe_psql(
123 'postgres', q{
124 INSERT INTO mine SELECT generate_series(10,20) AS x;
125 CHECKPOINT;
128 # Switch to a new segment and use the returned LSN to make sure that
129 # standbys have caught up to this point.
130 my $primary_lsn = $primary->safe_psql(
131 'postgres', q{
132 SELECT pg_switch_wal();
135 $primary->poll_query_until('postgres',
136 q{ SELECT last_archived_wal FROM pg_stat_archiver },
137 $segment_name_2)
138 or die "Timed out while waiting for archiving to finish";
140 # Test standby with archive_mode = on.
141 my $standby1 = PostgreSQL::Test::Cluster->new('standby');
142 $standby1->init_from_backup($primary, 'backup', has_restoring => 1);
143 $standby1->append_conf('postgresql.conf', "archive_mode = on");
144 my $standby1_data = $standby1->data_dir;
145 $standby1->start;
147 # Wait for the replay of the segment switch done previously, ensuring
148 # that all segments needed are restored from the archives.
149 $standby1->poll_query_until('postgres',
150 qq{ SELECT pg_wal_lsn_diff(pg_last_wal_replay_lsn(), '$primary_lsn') >= 0 }
151 ) or die "Timed out while waiting for xlog replay on standby1";
153 $standby1->safe_psql('postgres', q{CHECKPOINT});
155 # Recovery with archive_mode=on does not keep .ready signal files inherited
156 # from backup. Note that this WAL segment existed in the backup.
157 ok( !-f "$standby1_data/$segment_path_1_ready",
158 ".ready file for WAL segment $segment_name_1 present in backup got removed with archive_mode=on on standby"
161 # Recovery with archive_mode=on should not create .ready files.
162 # Note that this segment did not exist in the backup.
163 ok( !-f "$standby1_data/$segment_path_2_ready",
164 ".ready file for WAL segment $segment_name_2 not created on standby when archive_mode=on on standby"
167 # Recovery with archive_mode = on creates .done files.
168 ok( -f "$standby1_data/$segment_path_2_done",
169 ".done file for WAL segment $segment_name_2 created when archive_mode=on on standby"
172 # Test recovery with archive_mode = always, which should always keep
173 # .ready files if archiving is enabled, though here we want the archive
174 # command to fail to persist the .ready files. Note that this node
175 # has inherited the archive command of the previous cold backup that
176 # will cause archiving failures.
177 my $standby2 = PostgreSQL::Test::Cluster->new('standby2');
178 $standby2->init_from_backup($primary, 'backup', has_restoring => 1);
179 $standby2->append_conf('postgresql.conf', 'archive_mode = always');
180 my $standby2_data = $standby2->data_dir;
181 $standby2->start;
183 # Wait for the replay of the segment switch done previously, ensuring
184 # that all segments needed are restored from the archives.
185 $standby2->poll_query_until('postgres',
186 qq{ SELECT pg_wal_lsn_diff(pg_last_wal_replay_lsn(), '$primary_lsn') >= 0 }
187 ) or die "Timed out while waiting for xlog replay on standby2";
189 $standby2->safe_psql('postgres', q{CHECKPOINT});
191 ok( -f "$standby2_data/$segment_path_1_ready",
192 ".ready file for WAL segment $segment_name_1 existing in backup is kept with archive_mode=always on standby"
195 ok( -f "$standby2_data/$segment_path_2_ready",
196 ".ready file for WAL segment $segment_name_2 created with archive_mode=always on standby"
199 # Reset statistics of the archiver for the next checks.
200 $standby2->safe_psql('postgres', q{SELECT pg_stat_reset_shared('archiver')});
202 # Now crash the cluster to check that recovery step does not
203 # remove non-archived WAL segments on a standby where archiving
204 # is enabled.
205 $standby2->stop('immediate');
206 $standby2->start;
208 ok( -f "$standby2_data/$segment_path_1_ready",
209 "WAL segment still ready to archive after crash recovery on standby with archive_mode=always"
212 # Allow WAL archiving again, and wait for the segments to be archived.
213 $standby2->safe_psql(
214 'postgres', q{
215 ALTER SYSTEM RESET archive_command;
216 SELECT pg_reload_conf();
218 $standby2->poll_query_until('postgres',
219 q{SELECT last_archived_wal FROM pg_stat_archiver},
220 $segment_name_2)
221 or die "Timed out while waiting for archiving to finish";
223 is( $standby2->safe_psql(
224 'postgres', q{SELECT archived_count FROM pg_stat_archiver}),
225 '2',
226 "correct number of WAL segments archived from standby");
228 ok( !-f "$standby2_data/$segment_path_1_ready"
229 && !-f "$standby2_data/$segment_path_2_ready",
230 ".ready files removed after archive success with archive_mode=always on standby"
233 ok( -f "$standby2_data/$segment_path_1_done"
234 && -f "$standby2_data/$segment_path_2_done",
235 ".done files created after archive success with archive_mode=always on standby"