Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 376dc82

Browse files
author
Amit Kapila
committed
Add a test to verify that subscription to the standby works.
Author: Bertrand Drouvot Reviewed-by: Vignesh C, Alvaro Herrera, Amit Kapila Discussion: https://postgr.es/m/2fefa454-5a70-2174-ddbf-4a0e41537139@gmail.com
1 parent bedc1f0 commit 376dc82

File tree

2 files changed

+107
-5
lines changed

2 files changed

+107
-5
lines changed

src/test/perl/PostgreSQL/Test/Cluster.pm

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2611,8 +2611,14 @@ When doing physical replication, the standby is usually identified by
26112611
passing its PostgreSQL::Test::Cluster instance. When doing logical
26122612
replication, standby_name identifies a subscription.
26132613
2614-
The default value of target_lsn is $node->lsn('write'), which ensures
2615-
that the standby has caught up to what has been committed on the primary.
2614+
When not in recovery, the default value of target_lsn is $node->lsn('write'),
2615+
which ensures that the standby has caught up to what has been committed on
2616+
the primary.
2617+
2618+
When in recovery, the default value of target_lsn is $node->lsn('replay')
2619+
instead which ensures that the cascaded standby has caught up to what has been
2620+
replayed on the standby.
2621+
26162622
If you pass an explicit value of target_lsn, it should almost always be
26172623
the primary's write LSN; so this parameter is seldom needed except when
26182624
querying some intermediate replication node rather than the primary.
@@ -2644,7 +2650,16 @@ sub wait_for_catchup
26442650
}
26452651
if (!defined($target_lsn))
26462652
{
2647-
$target_lsn = $self->lsn('write');
2653+
my $isrecovery = $self->safe_psql('postgres', "SELECT pg_is_in_recovery()");
2654+
chomp($isrecovery);
2655+
if ($isrecovery eq 't')
2656+
{
2657+
$target_lsn = $self->lsn('replay');
2658+
}
2659+
else
2660+
{
2661+
$target_lsn = $self->lsn('write');
2662+
}
26482663
}
26492664
print "Waiting for replication conn "
26502665
. $standby_name . "'s "

src/test/recovery/t/035_standby_logical_decoding.pl

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@
1010
use PostgreSQL::Test::Utils;
1111
use Test::More;
1212

13-
my ($stdin, $stdout, $stderr, $cascading_stdout, $cascading_stderr, $ret, $handle, $slot);
13+
my ($stdin, $stdout, $stderr,
14+
$cascading_stdout, $cascading_stderr, $subscriber_stdin,
15+
$subscriber_stdout, $subscriber_stderr, $ret,
16+
$handle, $slot);
1417

1518
my $node_primary = PostgreSQL::Test::Cluster->new('primary');
1619
my $node_standby = PostgreSQL::Test::Cluster->new('standby');
1720
my $node_cascading_standby = PostgreSQL::Test::Cluster->new('cascading_standby');
21+
my $node_subscriber = PostgreSQL::Test::Cluster->new('subscriber');
1822
my $default_timeout = $PostgreSQL::Test::Utils::timeout_default;
23+
my $psql_timeout = IPC::Run::timer($default_timeout);
1924
my $res;
2025

2126
# Name for the physical slot on primary
@@ -267,7 +272,8 @@ sub check_for_invalidation
267272
has_streaming => 1,
268273
has_restoring => 1);
269274
$node_standby->append_conf('postgresql.conf',
270-
qq[primary_slot_name = '$primary_slotname']);
275+
qq[primary_slot_name = '$primary_slotname'
276+
max_replication_slots = 5]);
271277
$node_standby->start;
272278
$node_primary->wait_for_replay_catchup($node_standby);
273279
$node_standby->safe_psql('testdb', qq[SELECT * FROM pg_create_physical_replication_slot('$standby_physical_slotname');]);
@@ -285,6 +291,26 @@ sub check_for_invalidation
285291
$node_cascading_standby->start;
286292
$node_standby->wait_for_replay_catchup($node_cascading_standby, $node_primary);
287293

294+
#######################
295+
# Initialize subscriber node
296+
#######################
297+
$node_subscriber->init(allows_streaming => 'logical');
298+
$node_subscriber->start;
299+
300+
my %psql_subscriber = (
301+
'subscriber_stdin' => '',
302+
'subscriber_stdout' => '',
303+
'subscriber_stderr' => '');
304+
$psql_subscriber{run} = IPC::Run::start(
305+
[ 'psql', '-XA', '-f', '-', '-d', $node_subscriber->connstr('postgres') ],
306+
'<',
307+
\$psql_subscriber{subscriber_stdin},
308+
'>',
309+
\$psql_subscriber{subscriber_stdout},
310+
'2>',
311+
\$psql_subscriber{subscriber_stderr},
312+
$psql_timeout);
313+
288314
##################################################
289315
# Test that logical decoding on the standby
290316
# behaves correctly.
@@ -365,6 +391,67 @@ sub check_for_invalidation
365391
3,
366392
'replaying logical slot from another database fails');
367393

394+
##################################################
395+
# Test that we can subscribe on the standby with the publication
396+
# created on the primary.
397+
##################################################
398+
399+
# Create a table on the primary
400+
$node_primary->safe_psql('postgres',
401+
"CREATE TABLE tab_rep (a int primary key)");
402+
403+
# Create a table (same structure) on the subscriber node
404+
$node_subscriber->safe_psql('postgres',
405+
"CREATE TABLE tab_rep (a int primary key)");
406+
407+
# Create a publication on the primary
408+
$node_primary->safe_psql('postgres',
409+
"CREATE PUBLICATION tap_pub for table tab_rep");
410+
411+
$node_primary->wait_for_replay_catchup($node_standby);
412+
413+
# Subscribe on the standby
414+
my $standby_connstr = $node_standby->connstr . ' dbname=postgres';
415+
416+
# Not using safe_psql() here as it would wait for activity on the primary
417+
# and we wouldn't be able to launch pg_log_standby_snapshot() on the primary
418+
# while waiting.
419+
# psql_subscriber() allows to not wait synchronously.
420+
$psql_subscriber{subscriber_stdin} .=
421+
qq[CREATE SUBSCRIPTION tap_sub
422+
CONNECTION '$standby_connstr'
423+
PUBLICATION tap_pub
424+
WITH (copy_data = off);];
425+
$psql_subscriber{subscriber_stdin} .= "\n";
426+
427+
$psql_subscriber{run}->pump_nb();
428+
429+
# Speed up the subscription creation
430+
$node_primary->safe_psql('postgres', "SELECT pg_log_standby_snapshot()");
431+
432+
# Explicitly shut down psql instance gracefully - to avoid hangs
433+
# or worse on windows
434+
$psql_subscriber{subscriber_stdin} .= "\\q\n";
435+
$psql_subscriber{run}->finish;
436+
437+
$node_subscriber->wait_for_subscription_sync($node_standby, 'tap_sub');
438+
439+
# Insert some rows on the primary
440+
$node_primary->safe_psql('postgres',
441+
qq[INSERT INTO tab_rep select generate_series(1,10);]);
442+
443+
$node_primary->wait_for_replay_catchup($node_standby);
444+
$node_standby->wait_for_catchup('tap_sub');
445+
446+
# Check that the subscriber can see the rows inserted in the primary
447+
$result =
448+
$node_subscriber->safe_psql('postgres', "SELECT count(*) FROM tab_rep");
449+
is($result, qq(10), 'check replicated inserts after subscription on standby');
450+
451+
# We do not need the subscription and the subscriber anymore
452+
$node_subscriber->safe_psql('postgres', "DROP SUBSCRIPTION tap_sub");
453+
$node_subscriber->stop;
454+
368455
##################################################
369456
# Recovery conflict: Invalidate conflicting slots, including in-use slots
370457
# Scenario 1: hot_standby_feedback off and vacuum FULL

0 commit comments

Comments
 (0)