Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit071e3ad

Browse files
committed
Add basic TAP tests for the low-level backup method, take two
There are currently no tests for the low-level backup method wherepg_backup_start() and pg_backup_stop() are involved while taking afile-system backup. The tests introduced in this commit rely on abackground psql process to make sure that the backup is taken while thesession doing the SQL start and stop calls remains alive.Two cases are checked here with the backup taken:- Recovery without a backup_label, leading to a corrupted state.- Recovery with a backup_label, with a consistent state reached.Both cases cross-check some patterns in the logs generated when runningrecovery.Compared to the first attempt in99b4a63, this includes a couple offixes making the CI stable (5 runs succeeded here):- Add the file to the list of tests in meson.build.- Race condition with the first WAL segment that we expect in theprimary's archives, by adding a poll on pg_stat_archiver. The secondsegment with the checkpoint record is archived thanks to pg_backup_stopwaiting for it.- Fix failure of test where the backup_label does not exist. Thecluster inherits the configuration of the first node; it was attemptingto store segments in the first node's archives, triggering failures withcopy on Windows.- Fix failure of test on Windows because of incorrect parsing of thebackup_file in the success case. The data of the backup_label file isretrieved from the output pg_backup_stop() from a BackgroundPsql writtendirectly to the backup's data folder. This would include CRLFs (\r\n),causing the startup process to fail at the beginning of recovery whenparsing the backup_label because only LFs (\n) are allowed.Author: David SteeleDiscussion:https://postgr.es/m/f20fcc82-dadb-478d-beb4-1e2ffb0ace76@pgmasters.net
1 parentcc5ef90 commit071e3ad

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

‎src/test/recovery/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ tests += {
5050
't/039_end_of_wal.pl',
5151
't/040_standby_failover_slots_sync.pl',
5252
't/041_checkpoint_at_promote.pl',
53+
't/042_low_level_backup.pl',
5354
],
5455
},
5556
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
2+
# Copyright (c) 2024, PostgreSQL Global Development Group
3+
4+
# Test low-level backup method by using pg_backup_start() and pg_backup_stop()
5+
# to create backups.
6+
7+
use strict;
8+
use warnings;
9+
10+
use File::Copyqw(copy);
11+
use File::Pathqw(rmtree);
12+
use PostgreSQL::Test::Cluster;
13+
use PostgreSQL::Test::Utils;
14+
use Test::More;
15+
16+
# Start primary node with archiving.
17+
my$node_primary = PostgreSQL::Test::Cluster->new('primary');
18+
$node_primary->init(has_archiving=> 1,allows_streaming=> 1);
19+
$node_primary->start;
20+
21+
# Start backup.
22+
my$backup_name ='backup1';
23+
my$psql =$node_primary->background_psql('postgres');
24+
25+
$psql->query_safe("SET client_min_messages TO WARNING");
26+
$psql->set_query_timer_restart;
27+
$psql->query_safe("select pg_backup_start('test label')");
28+
29+
# Copy files.
30+
my$backup_dir =$node_primary->backup_dir .'/' .$backup_name;
31+
32+
PostgreSQL::Test::RecursiveCopy::copypath($node_primary->data_dir,
33+
$backup_dir);
34+
35+
# Cleanup some files/paths that should not be in the backup. There is no
36+
# attempt to handle all the exclusions done by pg_basebackup here, in part
37+
# because these are not required, but also to keep the test simple.
38+
#
39+
# Also remove pg_control because it needs to be copied later.
40+
unlink("$backup_dir/postmaster.pid")
41+
or BAIL_OUT("unable to unlink$backup_dir/postmaster.pid");
42+
unlink("$backup_dir/postmaster.opts")
43+
or BAIL_OUT("unable to unlink$backup_dir/postmaster.opts");
44+
unlink("$backup_dir/global/pg_control")
45+
or BAIL_OUT("unable to unlink$backup_dir/global/pg_control");
46+
47+
rmtree("$backup_dir/pg_wal")
48+
or BAIL_OUT("unable to unlink contents of$backup_dir/pg_wal");
49+
mkdir("$backup_dir/pg_wal");
50+
51+
# Create a table that will be used to verify that recovery started at the
52+
# correct location, rather than a location recorded in the control file.
53+
$node_primary->safe_psql('postgres',"create table canary (id int)");
54+
55+
# Advance the checkpoint location in pg_control past the location where the
56+
# backup started. Switch WAL to make it really clear that the location is
57+
# different and to put the checkpoint in a new WAL segment.
58+
my$segment_name =$node_primary->safe_psql('postgres',
59+
"select pg_walfile_name(pg_switch_wal())");
60+
61+
# Ensure that the segment just switched from is archived. The follow-up
62+
# tests depend on its presence to begin recovery.
63+
$node_primary->poll_query_until('postgres',
64+
q{SELECT last_archived_wal FROM pg_stat_archiver},
65+
$segment_name)
66+
ordie
67+
"Timed out while waiting for archiving of switched segment to finish";
68+
69+
$node_primary->safe_psql('postgres',"checkpoint");
70+
71+
# Copy pg_control last so it contains the new checkpoint.
72+
copy($node_primary->data_dir .'/global/pg_control',
73+
"$backup_dir/global/pg_control")
74+
or BAIL_OUT("unable to copy global/pg_control");
75+
76+
# Save the name segment that will be archived by pg_backup_stop().
77+
# This is copied to the pg_wal directory of the node whose recovery
78+
# is done without a backup_label.
79+
my$stop_segment_name =$node_primary->safe_psql('postgres',
80+
'SELECT pg_walfile_name(pg_current_wal_lsn())');
81+
82+
# Stop backup and get backup_label, the last segment is archived.
83+
my$backup_label =
84+
$psql->query_safe("select labelfile from pg_backup_stop()");
85+
86+
$psql->quit;
87+
88+
# Rather than writing out backup_label, try to recover the backup without
89+
# backup_label to demonstrate that recovery will not work correctly without it,
90+
# i.e. the canary table will be missing and the cluster will be corrupted.
91+
# Provide only the WAL segment that recovery will think it needs.
92+
#
93+
# The point of this test is to explicitly demonstrate that backup_label is
94+
# being used in a later test to get the correct recovery info.
95+
my$node_replica = PostgreSQL::Test::Cluster->new('replica_fail');
96+
$node_replica->init_from_backup($node_primary,$backup_name);
97+
$node_replica->append_conf('postgresql.conf',"archive_mode = off");
98+
99+
my$canary_query ="select count(*) from pg_class where relname = 'canary'";
100+
101+
copy(
102+
$node_primary->archive_dir ."/$stop_segment_name",
103+
$node_replica->data_dir ."/pg_wal/$stop_segment_name"
104+
)or BAIL_OUT("unable to copy$stop_segment_name");
105+
106+
$node_replica->start;
107+
108+
ok($node_replica->safe_psql('postgres',$canary_query) == 0,
109+
'canary is missing');
110+
111+
# Check log to ensure that crash recovery was used as there is no
112+
# backup_label.
113+
ok($node_replica->log_contains(
114+
'database system was not properly shut down; automatic recovery in progress'
115+
),
116+
'verify backup recovery performed with crash recovery');
117+
118+
$node_replica->teardown_node;
119+
$node_replica->clean_node;
120+
121+
# Save backup_label into the backup directory and recover using the primary's
122+
# archive. This time recovery will succeed and the canary table will be
123+
# present.
124+
openmy$fh,">>","$backup_dir/backup_label"
125+
ordie"could not open backup_label";
126+
# Binary mode is required for Windows, as the backup_label parsing is not
127+
# able to cope with CRLFs.
128+
binmode$fh;
129+
print$fh$backup_label;
130+
close$fh;
131+
132+
$node_replica = PostgreSQL::Test::Cluster->new('replica_success');
133+
$node_replica->init_from_backup($node_primary,$backup_name,
134+
has_restoring=> 1);
135+
$node_replica->start;
136+
137+
ok($node_replica->safe_psql('postgres',$canary_query) == 1,
138+
'canary is present');
139+
140+
# Check log to ensure that backup_label was used for recovery.
141+
ok($node_replica->log_contains('starting backup recovery with redo LSN'),
142+
'verify backup recovery performed with backup_label');
143+
144+
done_testing();

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp