diff --git a/src/test/subscription/meson.build b/src/test/subscription/meson.build index bd673a9d68..cdd2f8ba47 100644 --- a/src/test/subscription/meson.build +++ b/src/test/subscription/meson.build @@ -40,6 +40,7 @@ tests += { 't/031_column_list.pl', 't/032_subscribe_use_index.pl', 't/033_run_as_table_owner.pl', + 't/034_always_persist.pl', 't/100_bugs.pl', ], }, diff --git a/src/test/subscription/t/034_always_persist.pl b/src/test/subscription/t/034_always_persist.pl new file mode 100644 index 0000000000..91481cdaaf --- /dev/null +++ b/src/test/subscription/t/034_always_persist.pl @@ -0,0 +1,90 @@ + +# Copyright (c) 2023, PostgreSQL Global Development Group + +# Test logical replication slots are always persisted to disk during a shutdown +# checkpoint. + +use strict; +use warnings; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +sub compare_confirmed_flush +{ + my ($node) = @_; + + # Fetch checkPoint from the control file itself + my ($stdout, $stderr) = run_command([ 'pg_controldata', $node->data_dir ]); + my @control_data = split("\n", $stdout); + my $latest_checkpoint = undef; + foreach (@control_data) + { + if ($_ =~ /^Latest checkpoint location:\s*(.*)$/mg) + { + $latest_checkpoint = $1; + last; + } + } + die "No checkPoint in control file found\n" + unless defined($latest_checkpoint); + + # Fetch confirmed_flush_lsn from the pg_replication_slots + my $confirmed_flush = $node->safe_psql('postgres', + "SELECT confirmed_flush_lsn from pg_catalog.pg_replication_slots;" + ); + + # ...And compare them + ok($confirmed_flush eq $latest_checkpoint, + "Check confirmed_flush is same as latest checkpoint location"); + + return; +} + +# Initialize publisher node +my $node_publisher = PostgreSQL::Test::Cluster->new('pub'); +$node_publisher->init(allows_streaming => 'logical'); +$node_publisher->append_conf('postgresql.conf', q{ +autovacuum = off +checkpoint_timeout = 1h +}); +$node_publisher->start; + +# Create subscriber node +my $node_subscriber = PostgreSQL::Test::Cluster->new('sub'); +$node_subscriber->init(allows_streaming => 'logical'); +$node_subscriber->start; + +# Create table +$node_publisher->safe_psql('postgres', "CREATE TABLE test_tbl (id int)"); +$node_subscriber->safe_psql('postgres', "CREATE TABLE test_tbl (id int)"); + +# Insert some data +$node_publisher->safe_psql('postgres', + "INSERT INTO test_tbl VALUES (generate_series(1, 5));" +); + +# Setup logical replication +my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres'; +$node_publisher->safe_psql('postgres', "CREATE PUBLICATION pub FOR ALL TABLES"); +$node_subscriber->safe_psql('postgres', + "CREATE SUBSCRIPTION sub CONNECTION '$publisher_connstr' PUBLICATION pub" +); + +$node_subscriber->wait_for_subscription_sync($node_publisher, 'sub'); + +my $result = $node_subscriber->safe_psql('postgres', + "SELECT count(*) FROM test_tbl" +); + +is($result, qq(5), "check initial copy was done"); + +# Restart publisher once. If the slot has persisted, the confirmed_flush_lsn +# becomes the same as the latest checkpoint location, which means the +# SHUTDOWN_CHECKPOINT record. +$node_publisher->restart(); + +compare_confirmed_flush($node_publisher); + +done_testing();