Skip to content

Make pg_rewind work with encrypted WAL #335

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: TDE_REL_17_STABLE
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions contrib/pg_tde/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ tap_tests = [
't/013_crash_recovery.pl',
't/014_pg_waldump_basic.pl',
't/015_pg_waldump_fullpage.pl',
't/016_pg_rewind_basic.pl',
't/017_pg_rewind_databases.pl',
't/018_pg_rewind_extrafiles.pl',
't/019_pg_rewind_pg_xlog_symlink.pl',
't/020_pg_rewind_same_timeline.pl',
't/021_pg_rewind_options.pl',
't/022_pg_rewind_min_recovery_point.pl',
't/023_pg_rewind_growing_files.pl',
't/024_pg_rewind_keep_recycled_wals.pl',
]

tests += {
Expand Down
214 changes: 214 additions & 0 deletions contrib/pg_tde/t/016_pg_rewind_basic.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@

# Copyright (c) 2021-2024, PostgreSQL Global Development Group

use strict;
use warnings FATAL => 'all';
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 an in-place tablespace with some data on it.
primary_psql("CREATE TABLESPACE space_test LOCATION ''");
primary_psql("CREATE TABLE space_tbl (d text) TABLESPACE space_test");
primary_psql(
"INSERT INTO space_tbl VALUES ('in primary, before promotion')");

# 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
# standby'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");

# Insert some data in the in-place tablespace for the old primary and
# the standby.
primary_psql(
"INSERT INTO space_tbl VALUES ('in primary, after promotion')");
standby_psql(
"INSERT INTO space_tbl VALUES ('in standby, after promotion')");

# 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 space_tbl ORDER BY d',
qq(in primary, before promotion
in standby, after promotion
),
'table content');

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();
77 changes: 77 additions & 0 deletions contrib/pg_tde/t/017_pg_rewind_databases.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

# Copyright (c) 2021-2024, PostgreSQL Global Development Group

use strict;
use warnings FATAL => 'all';
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, ['-g']);
RewindTest::start_primary();

# Create a database in primary with a table.
primary_psql('CREATE DATABASE inprimary');
primary_psql('CREATE TABLE inprimary_tab (a int)', 'inprimary');

RewindTest::create_standby($test_mode);

# Create another database with another table, the creation is
# replicated to the standby.
primary_psql('CREATE DATABASE beforepromotion');
primary_psql('CREATE TABLE beforepromotion_tab (a int)',
'beforepromotion');

RewindTest::promote_standby();

# Create databases in the old primary and the new promoted standby.
primary_psql('CREATE DATABASE primary_afterpromotion');
primary_psql('CREATE TABLE primary_promotion_tab (a int)',
'primary_afterpromotion');
standby_psql('CREATE DATABASE standby_afterpromotion');
standby_psql('CREATE TABLE standby_promotion_tab (a int)',
'standby_afterpromotion');

# The clusters are now diverged.

RewindTest::run_pg_rewind($test_mode);

# Check that the correct databases are present after pg_rewind.
check_query(
'SELECT datname FROM pg_database ORDER BY 1',
qq(beforepromotion
inprimary
postgres
standby_afterpromotion
template0
template1
),
'database names');

# Permissions on PGDATA should have group permissions
SKIP:
{
skip "unix-style permissions not supported on Windows", 1
if ($windows_os || $Config::Config{osname} eq 'cygwin');

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

RewindTest::clean_rewind_test();
return;
}

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

done_testing();
Loading