summaryrefslogtreecommitdiffstats
path: root/src/bin/pg_rewind/t/001_basic.pl
blob: db9201f38e899a2541477f50db2191ea4f68da9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# Copyright (c) 2021-2022, PostgreSQL Global Development Group

use strict;
use warnings;
use PostgreSQL::Test::Utils;
use Test::More;

use FindBin;
use lib $FindBin::RealBin;

use RewindTest;

sub run_test
{
	my $test_mode = shift;

	RewindTest::setup_cluster($test_mode);
	RewindTest::start_primary();

	# Create a test table and insert a row in primary.
	primary_psql("CREATE TABLE tbl1 (d text)");
	primary_psql("INSERT INTO tbl1 VALUES ('in primary')");

	# This test table will be used to test truncation, i.e. the table
	# is extended in the old primary after promotion
	primary_psql("CREATE TABLE trunc_tbl (d text)");
	primary_psql("INSERT INTO trunc_tbl VALUES ('in primary')");

	# This test table will be used to test the "copy-tail" case, i.e. the
	# table is truncated in the old primary after promotion
	primary_psql("CREATE TABLE tail_tbl (id integer, d text)");
	primary_psql("INSERT INTO tail_tbl VALUES (0, 'in primary')");

	# This test table is dropped in the old primary after promotion.
	primary_psql("CREATE TABLE drop_tbl (d text)");
	primary_psql("INSERT INTO drop_tbl VALUES ('in primary')");

	primary_psql("CHECKPOINT");

	RewindTest::create_standby($test_mode);

	# Insert additional data on primary that will be replicated to standby
	primary_psql("INSERT INTO tbl1 values ('in primary, before promotion')");
	primary_psql(
		"INSERT INTO trunc_tbl values ('in primary, before promotion')");
	primary_psql(
		"INSERT INTO tail_tbl SELECT g, 'in primary, before promotion: ' || g FROM generate_series(1, 10000) g"
	);

	primary_psql('CHECKPOINT');

	RewindTest::promote_standby();

	# Insert a row in the old primary. This causes the primary and standby
	# to have "diverged", it's no longer possible to just apply the
	# standy's logs over primary directory - you need to rewind.
	primary_psql("INSERT INTO tbl1 VALUES ('in primary, after promotion')");

	# Also insert a new row in the standby, which won't be present in the
	# old primary.
	standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')");

	# Insert enough rows to trunc_tbl to extend the file. pg_rewind should
	# truncate it back to the old size.
	primary_psql(
		"INSERT INTO trunc_tbl SELECT 'in primary, after promotion: ' || g FROM generate_series(1, 10000) g"
	);

	# Truncate tail_tbl. pg_rewind should copy back the truncated part
	# (We cannot use an actual TRUNCATE command here, as that creates a
	# whole new relfilenode)
	primary_psql("DELETE FROM tail_tbl WHERE id > 10");
	primary_psql("VACUUM tail_tbl");

	# Drop drop_tbl. pg_rewind should copy it back.
	primary_psql(
		"insert into drop_tbl values ('in primary, after promotion')");
	primary_psql("DROP TABLE drop_tbl");

	# Before running pg_rewind, do a couple of extra tests with several
	# option combinations.  As the code paths taken by those tests
	# do not change for the "local" and "remote" modes, just run them
	# in "local" mode for simplicity's sake.
	if ($test_mode eq 'local')
	{
		my $primary_pgdata = $node_primary->data_dir;
		my $standby_pgdata = $node_standby->data_dir;

		# First check that pg_rewind fails if the target cluster is
		# not stopped as it fails to start up for the forced recovery
		# step.
		command_fails(
			[
				'pg_rewind',       '--debug',
				'--source-pgdata', $standby_pgdata,
				'--target-pgdata', $primary_pgdata,
				'--no-sync'
			],
			'pg_rewind with running target');

		# Again with --no-ensure-shutdown, which should equally fail.
		# This time pg_rewind complains without attempting to perform
		# recovery once.
		command_fails(
			[
				'pg_rewind',       '--debug',
				'--source-pgdata', $standby_pgdata,
				'--target-pgdata', $primary_pgdata,
				'--no-sync',       '--no-ensure-shutdown'
			],
			'pg_rewind --no-ensure-shutdown with running target');

		# Stop the target, and attempt to run with a local source
		# still running.  This fails as pg_rewind requires to have
		# a source cleanly stopped.
		$node_primary->stop;
		command_fails(
			[
				'pg_rewind',       '--debug',
				'--source-pgdata', $standby_pgdata,
				'--target-pgdata', $primary_pgdata,
				'--no-sync',       '--no-ensure-shutdown'
			],
			'pg_rewind with unexpected running source');

		# Stop the target cluster cleanly, and run again pg_rewind
		# with --dry-run mode.  If anything gets generated in the data
		# folder, the follow-up run of pg_rewind will most likely fail,
		# so keep this test as the last one of this subset.
		$node_standby->stop;
		command_ok(
			[
				'pg_rewind',       '--debug',
				'--source-pgdata', $standby_pgdata,
				'--target-pgdata', $primary_pgdata,
				'--no-sync',       '--dry-run'
			],
			'pg_rewind --dry-run');

		# Both clusters need to be alive moving forward.
		$node_standby->start;
		$node_primary->start;
	}

	RewindTest::run_pg_rewind($test_mode);

	check_query(
		'SELECT * FROM tbl1',
		qq(in primary
in primary, before promotion
in standby, after promotion
),
		'table content');

	check_query(
		'SELECT * FROM trunc_tbl',
		qq(in primary
in primary, before promotion
),
		'truncation');

	check_query(
		'SELECT count(*) FROM tail_tbl',
		qq(10001
),
		'tail-copy');

	check_query(
		'SELECT * FROM drop_tbl',
		qq(in primary
),
		'drop');

	# Permissions on PGDATA should be default
  SKIP:
	{
		skip "unix-style permissions not supported on Windows", 1
		  if ($windows_os);

		ok(check_mode_recursive($node_primary->data_dir(), 0700, 0600),
			'check PGDATA permissions');
	}

	RewindTest::clean_rewind_test();
	return;
}

# Run the test in both modes
run_test('local');
run_test('remote');
run_test('archive');

done_testing();