Add PostgreSQL::Test::Cluster::advance_wal
authorMichael Paquier <[email protected]>
Thu, 21 Dec 2023 01:19:17 +0000 (10:19 +0900)
committerMichael Paquier <[email protected]>
Thu, 21 Dec 2023 01:19:17 +0000 (10:19 +0900)
This is a function that makes a node jump by N WAL segments, which is
something a couple of tests have been relying on for some cases related
to streaming, replication slot limits and logical decoding on standbys.
Hence, this centralizes the logic, while making it cheaper by relying on
pg_logical_emit_message() to emit WAL records before switching to a new
segment.

Author: Bharath Rupireddy
Reviewed-by: Kyotaro Horiguchi, Euler Taveira
Discussion: https://postgr.es/m/CALj2ACU3R8QFCvDewHCMKjgb2w_-CMCyd6DAK=Jb-af14da5eg@mail.gmail.com

src/test/perl/PostgreSQL/Test/Cluster.pm
src/test/recovery/t/001_stream_rep.pl
src/test/recovery/t/019_replslot_limit.pl
src/test/recovery/t/035_standby_logical_decoding.pl

index 46cb2a65500e4f23a2324177591e2ead3a9a3307..f43e54282f2868a65593ff5b28eea5826f70dd38 100644 (file)
@@ -3197,6 +3197,31 @@ sub create_logical_slot_on_standby
 
 =pod
 
+=item $node->advance_wal(num)
+
+Advance WAL of node by given number of segments.
+
+=cut
+
+sub advance_wal
+{
+   my ($self, $num) = @_;
+
+   # Advance by $n segments (= (wal_segment_size * $num) bytes).
+   # pg_switch_wal() forces a WAL flush, making pg_logical_emit_message()
+   # safe to use in non-transactional mode.
+   for (my $i = 0; $i < $num; $i++)
+   {
+       $self->safe_psql(
+           'postgres', qq{
+           SELECT pg_logical_emit_message(false, '', 'foo');
+           SELECT pg_switch_wal();
+           });
+   }
+}
+
+=pod
+
 =back
 
 =cut
index 95f9b0d7726fb5f0278d1ad0d3e7c5ac5d431e76..f0de921b4b199e0b6a3ffd526426b5247cd04771 100644 (file)
@@ -522,11 +522,7 @@ $node_primary->safe_psql('postgres',
 my $segment_removed = $node_primary->safe_psql('postgres',
    'SELECT pg_walfile_name(pg_current_wal_lsn())');
 chomp($segment_removed);
-$node_primary->psql(
-   'postgres', "
-   CREATE TABLE tab_phys_slot (a int);
-   INSERT INTO tab_phys_slot VALUES (generate_series(1,10));
-   SELECT pg_switch_wal();");
+$node_primary->advance_wal(1);
 my $current_lsn =
   $node_primary->safe_psql('postgres', "SELECT pg_current_wal_lsn();");
 chomp($current_lsn);
index 7d94f157780a9fd27880f4567c1db988522ce252..6c244a555023ca86ed7ab8e86a48668357bcb5fd 100644 (file)
@@ -59,7 +59,7 @@ $result = $node_primary->safe_psql('postgres',
 is($result, "reserved|t", 'check the catching-up state');
 
 # Advance WAL by five segments (= 5MB) on primary
-advance_wal($node_primary, 1);
+$node_primary->advance_wal(1);
 $node_primary->safe_psql('postgres', "CHECKPOINT;");
 
 # The slot is always "safe" when fitting max_wal_size
@@ -69,7 +69,7 @@ $result = $node_primary->safe_psql('postgres',
 is($result, "reserved|t",
    'check that it is safe if WAL fits in max_wal_size');
 
-advance_wal($node_primary, 4);
+$node_primary->advance_wal(4);
 $node_primary->safe_psql('postgres', "CHECKPOINT;");
 
 # The slot is always "safe" when max_slot_wal_keep_size is not set
@@ -100,7 +100,7 @@ $result = $node_primary->safe_psql('postgres',
 is($result, "reserved", 'check that max_slot_wal_keep_size is working');
 
 # Advance WAL again then checkpoint, reducing remain by 2 MB.
-advance_wal($node_primary, 2);
+$node_primary->advance_wal(2);
 $node_primary->safe_psql('postgres', "CHECKPOINT;");
 
 # The slot is still working
@@ -118,7 +118,7 @@ $node_standby->stop;
 $result = $node_primary->safe_psql('postgres',
    "ALTER SYSTEM SET wal_keep_size to '8MB'; SELECT pg_reload_conf();");
 # Advance WAL again then checkpoint, reducing remain by 6 MB.
-advance_wal($node_primary, 6);
+$node_primary->advance_wal(6);
 $result = $node_primary->safe_psql('postgres',
    "SELECT wal_status as remain FROM pg_replication_slots WHERE slot_name = 'rep1'"
 );
@@ -134,7 +134,7 @@ $node_primary->wait_for_catchup($node_standby);
 $node_standby->stop;
 
 # Advance WAL again without checkpoint, reducing remain by 6 MB.
-advance_wal($node_primary, 6);
+$node_primary->advance_wal(6);
 
 # Slot gets into 'reserved' state
 $result = $node_primary->safe_psql('postgres',
@@ -145,7 +145,7 @@ is($result, "extended", 'check that the slot state changes to "extended"');
 $node_primary->safe_psql('postgres', "CHECKPOINT;");
 
 # Advance WAL again without checkpoint; remain goes to 0.
-advance_wal($node_primary, 1);
+$node_primary->advance_wal(1);
 
 # Slot gets into 'unreserved' state and safe_wal_size is negative
 $result = $node_primary->safe_psql('postgres',
@@ -174,7 +174,7 @@ $node_primary->safe_psql('postgres',
 
 # Advance WAL again. The slot loses the oldest segment by the next checkpoint
 my $logstart = -s $node_primary->logfile;
-advance_wal($node_primary, 7);
+$node_primary->advance_wal(7);
 
 # Now create another checkpoint and wait until the WARNING is issued
 $node_primary->safe_psql('postgres',
@@ -275,18 +275,12 @@ $node_standby->init_from_backup($node_primary2, $backup_name,
    has_streaming => 1);
 $node_standby->append_conf('postgresql.conf', "primary_slot_name = 'rep1'");
 $node_standby->start;
-my @result =
-  split(
-   '\n',
-   $node_primary2->safe_psql(
-       'postgres',
-       "CREATE TABLE tt();
-        DROP TABLE tt;
-        SELECT pg_switch_wal();
-        CHECKPOINT;
-        SELECT 'finished';",
-       timeout => $PostgreSQL::Test::Utils::timeout_default));
-is($result[1], 'finished', 'check if checkpoint command is not blocked');
+$node_primary2->advance_wal(1);
+$result = $node_primary2->safe_psql(
+   'postgres',
+   "CHECKPOINT; SELECT 'finished';",
+   timeout => $PostgreSQL::Test::Utils::timeout_default);
+is($result, 'finished', 'check if checkpoint command is not blocked');
 
 $node_primary2->stop;
 $node_standby->stop;
@@ -372,7 +366,7 @@ $logstart = -s $node_primary3->logfile;
 # freeze walsender and walreceiver. Slot will still be active, but walreceiver
 # won't get anything anymore.
 kill 'STOP', $senderpid, $receiverpid;
-advance_wal($node_primary3, 2);
+$node_primary3->advance_wal(2);
 
 my $msg_logged = 0;
 my $max_attempts = $PostgreSQL::Test::Utils::timeout_default;
@@ -418,19 +412,4 @@ kill 'CONT', $receiverpid;
 $node_primary3->stop;
 $node_standby3->stop;
 
-#####################################
-# Advance WAL of $node by $n segments
-sub advance_wal
-{
-   my ($node, $n) = @_;
-
-   # Advance by $n segments (= (wal_segment_size * $n) bytes) on primary.
-   for (my $i = 0; $i < $n; $i++)
-   {
-       $node->safe_psql('postgres',
-           "CREATE TABLE t (); DROP TABLE t; SELECT pg_switch_wal();");
-   }
-   return;
-}
-
 done_testing();
index 9c34c0d36cbfc1f018f3c546cb991f51add1b598..5d7c278d01a41f6a250bcb57c770ee31892839d9 100644 (file)
@@ -524,11 +524,8 @@ my $walfile_name = $node_primary->safe_psql('postgres',
 chomp($walfile_name);
 
 # Generate some activity and switch WAL file on the primary
-$node_primary->safe_psql(
-   'postgres', "create table retain_test(a int);
-                                    select pg_switch_wal();
-                                    insert into retain_test values(1);
-                                    checkpoint;");
+$node_primary->advance_wal(1);
+$node_primary->safe_psql('postgres', "checkpoint;");
 
 # Wait for the standby to catch up
 $node_primary->wait_for_replay_catchup($node_standby);