diff --git a/src/test/subscription/t/026_race.pl b/src/test/subscription/t/026_race.pl new file mode 100644 index 0000000000..cbbe6c34e2 --- /dev/null +++ b/src/test/subscription/t/026_race.pl @@ -0,0 +1,86 @@ + +# Copyright (c) 2021, PostgreSQL Global Development Group + +# Test subscriptions owned by non-superusers +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More; + +our $LOOPCOUNT = 100; +plan tests => 2 * $LOOPCOUNT; +my $result; + +# Setup + +my $node_publisher = PostgresNode->new('publisher'); +$node_publisher->init(allows_streaming => 'logical'); +$node_publisher->start; + +my $node_subscriber = PostgresNode->new('subscriber'); +$node_subscriber->init(allows_streaming => 'logical'); +$node_subscriber->start; + +my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres'; + +$node_publisher->safe_psql('postgres', qq( +CREATE TABLE t (i INTEGER); +ALTER TABLE t REPLICA IDENTITY FULL; +CREATE PUBLICATION pub FOR TABLE t; +)); + +$node_subscriber->safe_psql('postgres', qq( +CREATE TABLE t (i INTEGER); +CREATE SUBSCRIPTION sub CONNECTION '$publisher_connstr' PUBLICATION pub; +CREATE TABLE b (LIKE t); +)); + +# Wait for initial sync of all subscriptions. +my $synced_query = + "SELECT count(1) = 0 FROM pg_subscription_rel WHERE srsubstate NOT IN ('r', 's');"; +$node_subscriber->poll_query_until('postgres', $synced_query) + or die "Timed out while waiting for subscriber to synchronize data"; + +# Upon first entry to this loop, the subscription is enabled +foreach my $loop (1..$LOOPCOUNT) +{ + my $even = $loop * 2; + my $odd = ($loop * 2) + 1; + + # The subscription is enabled. This even number is fair game for + # replication. + $node_publisher->safe_psql('postgres', "INSERT INTO t (i) VALUES ($even)"); + + # We may replicate the even number before the subscription is disabled, but + # maybe not. + $node_subscriber->safe_psql('postgres', "ALTER SUBSCRIPTION sub DISABLE"); + + # The subscription is now disabled, but workers on the subscriber side may + # not have gotten the message yet. As such, this odd number may slip + # through. + $node_publisher->safe_psql('postgres', "INSERT INTO t (i) VALUES ($odd)"); + + # See if we can catch any odd numbers in the subscriber's copy of table t + $result = $node_subscriber->safe_psql('postgres', + "SELECT COUNT(*) FROM t WHERE i % 2 = 1"); + is ($result, 0, "No odd numbers in subscriber copy of table t before delete on publisher"); + + # Clear out all values on the publisher side, so that the odd number cannot + # be replicated after we re-enable the subscription. Of course, it may have + # already slipped through, and it is also possible that the even number has + # not replicated yet. + # + # Since the publication only publishes INSERTs, this delete should only have + # effect on the publisher side. + $node_publisher->safe_psql('postgres', "DELETE FROM t WHERE i = $odd"); + + # Enable the subscription for the next loop. Note that at this point, the + # table is empty on the publisher side. + $node_subscriber->safe_psql('postgres', "ALTER SUBSCRIPTION sub ENABLE"); + + # See if we can catch an odd number before the delete is propogated + $result = $node_subscriber->safe_psql('postgres', + "SELECT COUNT(*) FROM t WHERE i % 2 = 1"); + is ($result, 0, "No odd numbers in subscriber copy of table t after delete on publisher"); +}