1# Test for promotion handling with WAL records generated post-promotion
2# before the first checkpoint is generated.  This test case checks for
3# invalid page references at replay based on the minimum consistent
4# recovery point defined.
5use strict;
6use warnings;
7use PostgresNode;
8use TestLib;
9use Test::More tests => 1;
10
11# Initialize primary node
12my $alpha = get_new_node('alpha');
13$alpha->init(allows_streaming => 1);
14# Setting wal_log_hints to off is important to get invalid page
15# references.
16$alpha->append_conf("postgresql.conf", <<EOF);
17wal_log_hints = off
18EOF
19
20# Start the primary
21$alpha->start;
22
23# setup/start a standby
24$alpha->backup('bkp');
25my $bravo = get_new_node('bravo');
26$bravo->init_from_backup($alpha, 'bkp', has_streaming => 1);
27$bravo->append_conf('postgresql.conf', <<EOF);
28checkpoint_timeout=1h
29checkpoint_completion_target=0.9
30EOF
31$bravo->start;
32
33# Dummy table for the upcoming tests.
34$alpha->safe_psql('postgres', 'create table test1 (a int)');
35$alpha->safe_psql('postgres', 'insert into test1 select generate_series(1, 10000)');
36
37# take a checkpoint
38$alpha->safe_psql('postgres', 'checkpoint');
39
40# The following vacuum will set visibility map bits and create
41# problematic WAL records.
42$alpha->safe_psql('postgres', 'vacuum verbose test1');
43# Wait for last record to have been replayed on the standby.
44$alpha->wait_for_catchup($bravo, 'replay',
45						 $alpha->lsn('insert'));
46
47# Now force a checkpoint on the standby. This seems unnecessary but for "some"
48# reason, the previous checkpoint on the primary does not reflect on the standby
49# and without an explicit checkpoint, it may start redo recovery from a much
50# older point, which includes even create table and initial page additions.
51$bravo->safe_psql('postgres', 'checkpoint');
52
53# Now just use a dummy table and run some operations to move minRecoveryPoint
54# beyond the previous vacuum.
55$alpha->safe_psql('postgres', 'create table test2 (a int, b text)');
56$alpha->safe_psql('postgres', 'insert into test2 select generate_series(1,10000), md5(random()::text)');
57$alpha->safe_psql('postgres', 'truncate test2');
58
59# Wait again for all records to be replayed.
60$alpha->wait_for_catchup($bravo, 'replay',
61						 $alpha->lsn('insert'));
62
63# Do the promotion, which reinitializes minRecoveryPoint in the control
64# file so as WAL is replayed up to the end.
65$bravo->promote;
66
67# Truncate the table on the promoted standby, vacuum and extend it
68# again to create new page references.  The first post-recovery checkpoint
69# has not happened yet.
70$bravo->safe_psql('postgres', 'truncate test1');
71$bravo->safe_psql('postgres', 'vacuum verbose test1');
72$bravo->safe_psql('postgres', 'insert into test1 select generate_series(1,1000)');
73
74# Now crash-stop the promoted standby and restart.  This makes sure that
75# replay does not see invalid page references because of an invalid
76# minimum consistent recovery point.
77$bravo->stop('immediate');
78$bravo->start;
79
80# Check state of the table after full crash recovery.  All its data should
81# be here.
82my $psql_out;
83$bravo->psql(
84	'postgres',
85	"SELECT count(*) FROM test1",
86	stdout => \$psql_out);
87is($psql_out, '1000', "Check that table state is correct");
88