postgresql/src/test/recovery/t/033_replay_tsp_drops.pl

157 lines
5.0 KiB
Perl

# Copyright (c) 2021-2023, PostgreSQL Global Development Group
# Test replay of tablespace/database creation/drop
use strict;
use warnings;
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;
use Time::HiRes qw(usleep);
sub test_tablespace
{
my ($strategy) = @_;
my $node_primary = PostgreSQL::Test::Cluster->new("primary1_$strategy");
$node_primary->init(allows_streaming => 1);
$node_primary->start;
$node_primary->psql(
'postgres',
qq[
SET allow_in_place_tablespaces=on;
CREATE TABLESPACE dropme_ts1 LOCATION '';
CREATE TABLESPACE dropme_ts2 LOCATION '';
CREATE TABLESPACE source_ts LOCATION '';
CREATE TABLESPACE target_ts LOCATION '';
CREATE DATABASE template_db IS_TEMPLATE = true;
SELECT pg_create_physical_replication_slot('slot', true);
]);
my $backup_name = 'my_backup';
$node_primary->backup($backup_name);
my $node_standby = PostgreSQL::Test::Cluster->new("standby2_$strategy");
$node_standby->init_from_backup($node_primary, $backup_name,
has_streaming => 1);
$node_standby->append_conf('postgresql.conf',
"allow_in_place_tablespaces = on");
$node_standby->append_conf('postgresql.conf',
"primary_slot_name = slot");
$node_standby->start;
# Make sure the connection is made
$node_primary->wait_for_catchup($node_standby, 'write');
# Do immediate shutdown just after a sequence of CREATE DATABASE / DROP
# DATABASE / DROP TABLESPACE. This causes CREATE DATABASE WAL records
# to be applied to already-removed directories.
my $query = q[
CREATE DATABASE dropme_db1 WITH TABLESPACE dropme_ts1 STRATEGY=<STRATEGY>;
CREATE TABLE t (a int) TABLESPACE dropme_ts2;
CREATE DATABASE dropme_db2 WITH TABLESPACE dropme_ts2 STRATEGY=<STRATEGY>;
CREATE DATABASE moveme_db TABLESPACE source_ts STRATEGY=<STRATEGY>;
ALTER DATABASE moveme_db SET TABLESPACE target_ts;
CREATE DATABASE newdb TEMPLATE template_db STRATEGY=<STRATEGY>;
ALTER DATABASE template_db IS_TEMPLATE = false;
DROP DATABASE dropme_db1;
DROP TABLE t;
DROP DATABASE dropme_db2; DROP TABLESPACE dropme_ts2;
DROP TABLESPACE source_ts;
DROP DATABASE template_db;
];
$query =~ s/<STRATEGY>/$strategy/g;
$node_primary->safe_psql('postgres', $query);
$node_primary->wait_for_catchup($node_standby, 'write');
# show "create missing directory" log message
$node_standby->safe_psql('postgres',
"ALTER SYSTEM SET log_min_messages TO debug1;");
$node_standby->stop('immediate');
# Should restart ignoring directory creation error.
is($node_standby->start(fail_ok => 1),
1, "standby node started for $strategy");
$node_standby->stop('immediate');
}
test_tablespace("FILE_COPY");
test_tablespace("WAL_LOG");
# Ensure that a missing tablespace directory during create database
# replay immediately causes panic if the standby has already reached
# consistent state (archive recovery is in progress). This is
# effective only for CREATE DATABASE WITH STRATEGY=FILE_COPY.
my $node_primary = PostgreSQL::Test::Cluster->new('primary2');
$node_primary->init(allows_streaming => 1);
$node_primary->start;
# Create tablespace
$node_primary->safe_psql(
'postgres', q[
SET allow_in_place_tablespaces=on;
CREATE TABLESPACE ts1 LOCATION ''
]);
$node_primary->safe_psql('postgres',
"CREATE DATABASE db1 WITH TABLESPACE ts1 STRATEGY=FILE_COPY");
# Take backup
my $backup_name = 'my_backup';
$node_primary->backup($backup_name);
my $node_standby = PostgreSQL::Test::Cluster->new('standby3');
$node_standby->init_from_backup($node_primary, $backup_name,
has_streaming => 1);
$node_standby->append_conf('postgresql.conf',
"allow_in_place_tablespaces = on");
$node_standby->start;
# Make sure standby reached consistency and starts accepting connections
$node_standby->poll_query_until('postgres', 'SELECT 1', '1');
# Remove standby tablespace directory so it will be missing when
# replay resumes.
my $tspoid = $node_standby->safe_psql('postgres',
"SELECT oid FROM pg_tablespace WHERE spcname = 'ts1';");
my $tspdir = $node_standby->data_dir . "/pg_tblspc/$tspoid";
File::Path::rmtree($tspdir);
my $logstart = -s $node_standby->logfile;
# Create a database in the tablespace and a table in default tablespace
$node_primary->safe_psql(
'postgres',
q[
CREATE TABLE should_not_replay_insertion(a int);
CREATE DATABASE db2 WITH TABLESPACE ts1 STRATEGY=FILE_COPY;
INSERT INTO should_not_replay_insertion VALUES (1);
]);
# Standby should fail and should not silently skip replaying the wal
# In this test, PANIC turns into WARNING by allow_in_place_tablespaces.
# Check the log messages instead of confirming standby failure.
my $max_attempts = $PostgreSQL::Test::Utils::timeout_default * 10;
while ($max_attempts-- >= 0)
{
last
if (
find_in_log(
$node_standby, qr!WARNING: ( [A-Z0-9]+:)? creating missing directory: pg_tblspc/!,
$logstart));
usleep(100_000);
}
ok($max_attempts > 0, "invalid directory creation is detected");
done_testing();
# find $pat in logfile of $node after $off-th byte
sub find_in_log
{
my ($node, $pat, $off) = @_;
my $log = PostgreSQL::Test::Utils::slurp_file($node->logfile, $off);
return $log =~ m/$pat/;
}