Add a failover option to subscriptions.
This commit introduces a new subscription option named 'failover', which
provides users with the ability to set the failover property of the
replication slot on the publisher when creating or altering a
subscription.
This uses the replication commands introduced by commit 7329240437 to
enable the failover option for a logical replication slot.
If the failover option is set to true, the associated replication slots
(i.e. the main slot and the table sync slots) in the upstream database are
enabled to be synchronized to the standbys. Note that the capability to
sync the replication slots will be added in subsequent commits.
Thanks to Masahiko Sawada for the design inputs.
Author: Shveta Malik, Hou Zhijie, Ajin Cherian
Reviewed-by: Peter Smith, Bertrand Drouvot, Dilip Kumar, Masahiko Sawada, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-01-30 12:01:09 +01:00
|
|
|
|
|
|
|
# Copyright (c) 2024, PostgreSQL Global Development Group
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
use PostgreSQL::Test::Cluster;
|
|
|
|
use PostgreSQL::Test::Utils;
|
|
|
|
use Test::More;
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# Test that when a subscription with failover enabled is created, it will alter
|
|
|
|
# the failover property of the corresponding slot on the publisher.
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
# Create publisher
|
|
|
|
my $publisher = PostgreSQL::Test::Cluster->new('publisher');
|
|
|
|
$publisher->init(allows_streaming => 'logical');
|
2024-02-16 10:12:50 +01:00
|
|
|
# Disable autovacuum to avoid generating xid during stats update as otherwise
|
|
|
|
# the new XID could then be replicated to standby at some random point making
|
|
|
|
# slots at primary lag behind standby during slot sync.
|
|
|
|
$publisher->append_conf('postgresql.conf', 'autovacuum = off');
|
Add a failover option to subscriptions.
This commit introduces a new subscription option named 'failover', which
provides users with the ability to set the failover property of the
replication slot on the publisher when creating or altering a
subscription.
This uses the replication commands introduced by commit 7329240437 to
enable the failover option for a logical replication slot.
If the failover option is set to true, the associated replication slots
(i.e. the main slot and the table sync slots) in the upstream database are
enabled to be synchronized to the standbys. Note that the capability to
sync the replication slots will be added in subsequent commits.
Thanks to Masahiko Sawada for the design inputs.
Author: Shveta Malik, Hou Zhijie, Ajin Cherian
Reviewed-by: Peter Smith, Bertrand Drouvot, Dilip Kumar, Masahiko Sawada, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-01-30 12:01:09 +01:00
|
|
|
$publisher->start;
|
|
|
|
|
|
|
|
$publisher->safe_psql('postgres',
|
|
|
|
"CREATE PUBLICATION regress_mypub FOR ALL TABLES;");
|
|
|
|
|
|
|
|
my $publisher_connstr = $publisher->connstr . ' dbname=postgres';
|
|
|
|
|
|
|
|
# Create a subscriber node, wait for sync to complete
|
|
|
|
my $subscriber1 = PostgreSQL::Test::Cluster->new('subscriber1');
|
|
|
|
$subscriber1->init;
|
|
|
|
$subscriber1->start;
|
|
|
|
|
|
|
|
# Create a slot on the publisher with failover disabled
|
|
|
|
$publisher->safe_psql('postgres',
|
|
|
|
"SELECT 'init' FROM pg_create_logical_replication_slot('lsub1_slot', 'pgoutput', false, false, false);"
|
|
|
|
);
|
|
|
|
|
|
|
|
# Confirm that the failover flag on the slot is turned off
|
|
|
|
is( $publisher->safe_psql(
|
|
|
|
'postgres',
|
|
|
|
q{SELECT failover from pg_replication_slots WHERE slot_name = 'lsub1_slot';}
|
|
|
|
),
|
|
|
|
"f",
|
|
|
|
'logical slot has failover false on the publisher');
|
|
|
|
|
|
|
|
# Create a subscription (using the same slot created above) that enables
|
|
|
|
# failover.
|
|
|
|
$subscriber1->safe_psql('postgres',
|
|
|
|
"CREATE SUBSCRIPTION regress_mysub1 CONNECTION '$publisher_connstr' PUBLICATION regress_mypub WITH (slot_name = lsub1_slot, copy_data=false, failover = true, create_slot = false, enabled = false);"
|
|
|
|
);
|
|
|
|
|
|
|
|
# Confirm that the failover flag on the slot has now been turned on
|
|
|
|
is( $publisher->safe_psql(
|
|
|
|
'postgres',
|
|
|
|
q{SELECT failover from pg_replication_slots WHERE slot_name = 'lsub1_slot';}
|
|
|
|
),
|
|
|
|
"t",
|
|
|
|
'logical slot has failover true on the publisher');
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# Test that changing the failover property of a subscription updates the
|
|
|
|
# corresponding failover property of the slot.
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
# Disable failover
|
|
|
|
$subscriber1->safe_psql('postgres',
|
|
|
|
"ALTER SUBSCRIPTION regress_mysub1 SET (failover = false)");
|
|
|
|
|
|
|
|
# Confirm that the failover flag on the slot has now been turned off
|
|
|
|
is( $publisher->safe_psql(
|
|
|
|
'postgres',
|
|
|
|
q{SELECT failover from pg_replication_slots WHERE slot_name = 'lsub1_slot';}
|
|
|
|
),
|
|
|
|
"f",
|
|
|
|
'logical slot has failover false on the publisher');
|
|
|
|
|
|
|
|
# Enable failover
|
|
|
|
$subscriber1->safe_psql('postgres',
|
|
|
|
"ALTER SUBSCRIPTION regress_mysub1 SET (failover = true)");
|
|
|
|
|
|
|
|
# Confirm that the failover flag on the slot has now been turned on
|
|
|
|
is( $publisher->safe_psql(
|
|
|
|
'postgres',
|
|
|
|
q{SELECT failover from pg_replication_slots WHERE slot_name = 'lsub1_slot';}
|
|
|
|
),
|
|
|
|
"t",
|
|
|
|
'logical slot has failover true on the publisher');
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# Test that the failover option cannot be changed for enabled subscriptions.
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
# Enable subscription
|
|
|
|
$subscriber1->safe_psql('postgres',
|
|
|
|
"ALTER SUBSCRIPTION regress_mysub1 ENABLE");
|
|
|
|
|
|
|
|
# Disable failover for enabled subscription
|
|
|
|
my ($result, $stdout, $stderr) = $subscriber1->psql('postgres',
|
|
|
|
"ALTER SUBSCRIPTION regress_mysub1 SET (failover = false)");
|
|
|
|
ok( $stderr =~ /ERROR: cannot set failover for enabled subscription/,
|
|
|
|
"altering failover is not allowed for enabled subscription");
|
|
|
|
|
Add a slot synchronization function.
This commit introduces a new SQL function pg_sync_replication_slots()
which is used to synchronize the logical replication slots from the
primary server to the physical standby so that logical replication can be
resumed after a failover or planned switchover.
A new 'synced' flag is introduced in pg_replication_slots view, indicating
whether the slot has been synchronized from the primary server. On a
standby, synced slots cannot be dropped or consumed, and any attempt to
perform logical decoding on them will result in an error.
The logical replication slots on the primary can be synchronized to the
hot standby by using the 'failover' parameter of
pg-create-logical-replication-slot(), or by using the 'failover' option of
CREATE SUBSCRIPTION during slot creation, and then calling
pg_sync_replication_slots() on standby. For the synchronization to work,
it is mandatory to have a physical replication slot between the primary
and the standby aka 'primary_slot_name' should be configured on the
standby, and 'hot_standby_feedback' must be enabled on the standby. It is
also necessary to specify a valid 'dbname' in the 'primary_conninfo'.
If a logical slot is invalidated on the primary, then that slot on the
standby is also invalidated.
If a logical slot on the primary is valid but is invalidated on the
standby, then that slot is dropped but will be recreated on the standby in
the next pg_sync_replication_slots() call provided the slot still exists
on the primary server. It is okay to recreate such slots as long as these
are not consumable on standby (which is the case currently). This
situation may occur due to the following reasons:
- The 'max_slot_wal_keep_size' on the standby is insufficient to retain
WAL records from the restart_lsn of the slot.
- 'primary_slot_name' is temporarily reset to null and the physical slot
is removed.
The slot synchronization status on the standby can be monitored using the
'synced' column of pg_replication_slots view.
A functionality to automatically synchronize slots by a background worker
and allow logical walsenders to wait for the physical will be done in
subsequent commits.
Author: Hou Zhijie, Shveta Malik, Ajin Cherian based on an earlier version by Peter Eisentraut
Reviewed-by: Masahiko Sawada, Bertrand Drouvot, Peter Smith, Dilip Kumar, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-02-14 05:15:36 +01:00
|
|
|
##################################################
|
|
|
|
# Test that pg_sync_replication_slots() cannot be executed on a non-standby server.
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
($result, $stdout, $stderr) =
|
|
|
|
$publisher->psql('postgres', "SELECT pg_sync_replication_slots();");
|
|
|
|
ok( $stderr =~
|
|
|
|
/ERROR: replication slots can only be synchronized to a standby server/,
|
|
|
|
"cannot sync slots on a non-standby server");
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# Test logical failover slots on the standby
|
|
|
|
# Configure standby1 to replicate and synchronize logical slots configured
|
|
|
|
# for failover on the primary
|
|
|
|
#
|
|
|
|
# failover slot lsub1_slot ->| ----> subscriber1 (connected via logical replication)
|
|
|
|
# failover slot lsub2_slot | inactive
|
|
|
|
# primary ---> |
|
|
|
|
# physical slot sb1_slot --->| ----> standby1 (connected via streaming replication)
|
|
|
|
# | lsub1_slot, lsub2_slot (synced_slot)
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
my $primary = $publisher;
|
|
|
|
my $backup_name = 'backup';
|
|
|
|
$primary->backup($backup_name);
|
|
|
|
|
|
|
|
# Create a standby
|
|
|
|
my $standby1 = PostgreSQL::Test::Cluster->new('standby1');
|
|
|
|
$standby1->init_from_backup(
|
|
|
|
$primary, $backup_name,
|
|
|
|
has_streaming => 1,
|
|
|
|
has_restoring => 1);
|
|
|
|
|
2024-02-16 05:43:51 +01:00
|
|
|
# Increase the log_min_messages setting to DEBUG2 on both the standby and
|
|
|
|
# primary to debug test failures, if any.
|
Add a slot synchronization function.
This commit introduces a new SQL function pg_sync_replication_slots()
which is used to synchronize the logical replication slots from the
primary server to the physical standby so that logical replication can be
resumed after a failover or planned switchover.
A new 'synced' flag is introduced in pg_replication_slots view, indicating
whether the slot has been synchronized from the primary server. On a
standby, synced slots cannot be dropped or consumed, and any attempt to
perform logical decoding on them will result in an error.
The logical replication slots on the primary can be synchronized to the
hot standby by using the 'failover' parameter of
pg-create-logical-replication-slot(), or by using the 'failover' option of
CREATE SUBSCRIPTION during slot creation, and then calling
pg_sync_replication_slots() on standby. For the synchronization to work,
it is mandatory to have a physical replication slot between the primary
and the standby aka 'primary_slot_name' should be configured on the
standby, and 'hot_standby_feedback' must be enabled on the standby. It is
also necessary to specify a valid 'dbname' in the 'primary_conninfo'.
If a logical slot is invalidated on the primary, then that slot on the
standby is also invalidated.
If a logical slot on the primary is valid but is invalidated on the
standby, then that slot is dropped but will be recreated on the standby in
the next pg_sync_replication_slots() call provided the slot still exists
on the primary server. It is okay to recreate such slots as long as these
are not consumable on standby (which is the case currently). This
situation may occur due to the following reasons:
- The 'max_slot_wal_keep_size' on the standby is insufficient to retain
WAL records from the restart_lsn of the slot.
- 'primary_slot_name' is temporarily reset to null and the physical slot
is removed.
The slot synchronization status on the standby can be monitored using the
'synced' column of pg_replication_slots view.
A functionality to automatically synchronize slots by a background worker
and allow logical walsenders to wait for the physical will be done in
subsequent commits.
Author: Hou Zhijie, Shveta Malik, Ajin Cherian based on an earlier version by Peter Eisentraut
Reviewed-by: Masahiko Sawada, Bertrand Drouvot, Peter Smith, Dilip Kumar, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-02-14 05:15:36 +01:00
|
|
|
my $connstr_1 = $primary->connstr;
|
|
|
|
$standby1->append_conf(
|
|
|
|
'postgresql.conf', qq(
|
|
|
|
hot_standby_feedback = on
|
|
|
|
primary_slot_name = 'sb1_slot'
|
|
|
|
primary_conninfo = '$connstr_1 dbname=postgres'
|
2024-02-16 05:43:51 +01:00
|
|
|
log_min_messages = 'debug2'
|
Add a slot synchronization function.
This commit introduces a new SQL function pg_sync_replication_slots()
which is used to synchronize the logical replication slots from the
primary server to the physical standby so that logical replication can be
resumed after a failover or planned switchover.
A new 'synced' flag is introduced in pg_replication_slots view, indicating
whether the slot has been synchronized from the primary server. On a
standby, synced slots cannot be dropped or consumed, and any attempt to
perform logical decoding on them will result in an error.
The logical replication slots on the primary can be synchronized to the
hot standby by using the 'failover' parameter of
pg-create-logical-replication-slot(), or by using the 'failover' option of
CREATE SUBSCRIPTION during slot creation, and then calling
pg_sync_replication_slots() on standby. For the synchronization to work,
it is mandatory to have a physical replication slot between the primary
and the standby aka 'primary_slot_name' should be configured on the
standby, and 'hot_standby_feedback' must be enabled on the standby. It is
also necessary to specify a valid 'dbname' in the 'primary_conninfo'.
If a logical slot is invalidated on the primary, then that slot on the
standby is also invalidated.
If a logical slot on the primary is valid but is invalidated on the
standby, then that slot is dropped but will be recreated on the standby in
the next pg_sync_replication_slots() call provided the slot still exists
on the primary server. It is okay to recreate such slots as long as these
are not consumable on standby (which is the case currently). This
situation may occur due to the following reasons:
- The 'max_slot_wal_keep_size' on the standby is insufficient to retain
WAL records from the restart_lsn of the slot.
- 'primary_slot_name' is temporarily reset to null and the physical slot
is removed.
The slot synchronization status on the standby can be monitored using the
'synced' column of pg_replication_slots view.
A functionality to automatically synchronize slots by a background worker
and allow logical walsenders to wait for the physical will be done in
subsequent commits.
Author: Hou Zhijie, Shveta Malik, Ajin Cherian based on an earlier version by Peter Eisentraut
Reviewed-by: Masahiko Sawada, Bertrand Drouvot, Peter Smith, Dilip Kumar, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-02-14 05:15:36 +01:00
|
|
|
));
|
|
|
|
|
2024-02-16 05:43:51 +01:00
|
|
|
$primary->append_conf('postgresql.conf', "log_min_messages = 'debug2'");
|
|
|
|
$primary->reload;
|
|
|
|
|
Add a slot synchronization function.
This commit introduces a new SQL function pg_sync_replication_slots()
which is used to synchronize the logical replication slots from the
primary server to the physical standby so that logical replication can be
resumed after a failover or planned switchover.
A new 'synced' flag is introduced in pg_replication_slots view, indicating
whether the slot has been synchronized from the primary server. On a
standby, synced slots cannot be dropped or consumed, and any attempt to
perform logical decoding on them will result in an error.
The logical replication slots on the primary can be synchronized to the
hot standby by using the 'failover' parameter of
pg-create-logical-replication-slot(), or by using the 'failover' option of
CREATE SUBSCRIPTION during slot creation, and then calling
pg_sync_replication_slots() on standby. For the synchronization to work,
it is mandatory to have a physical replication slot between the primary
and the standby aka 'primary_slot_name' should be configured on the
standby, and 'hot_standby_feedback' must be enabled on the standby. It is
also necessary to specify a valid 'dbname' in the 'primary_conninfo'.
If a logical slot is invalidated on the primary, then that slot on the
standby is also invalidated.
If a logical slot on the primary is valid but is invalidated on the
standby, then that slot is dropped but will be recreated on the standby in
the next pg_sync_replication_slots() call provided the slot still exists
on the primary server. It is okay to recreate such slots as long as these
are not consumable on standby (which is the case currently). This
situation may occur due to the following reasons:
- The 'max_slot_wal_keep_size' on the standby is insufficient to retain
WAL records from the restart_lsn of the slot.
- 'primary_slot_name' is temporarily reset to null and the physical slot
is removed.
The slot synchronization status on the standby can be monitored using the
'synced' column of pg_replication_slots view.
A functionality to automatically synchronize slots by a background worker
and allow logical walsenders to wait for the physical will be done in
subsequent commits.
Author: Hou Zhijie, Shveta Malik, Ajin Cherian based on an earlier version by Peter Eisentraut
Reviewed-by: Masahiko Sawada, Bertrand Drouvot, Peter Smith, Dilip Kumar, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-02-14 05:15:36 +01:00
|
|
|
$primary->psql('postgres',
|
|
|
|
q{SELECT pg_create_logical_replication_slot('lsub2_slot', 'test_decoding', false, false, true);}
|
|
|
|
);
|
|
|
|
|
|
|
|
$primary->psql('postgres',
|
|
|
|
q{SELECT pg_create_physical_replication_slot('sb1_slot');});
|
|
|
|
|
|
|
|
# Start the standby so that slot syncing can begin
|
|
|
|
$standby1->start;
|
|
|
|
|
|
|
|
$primary->wait_for_catchup('regress_mysub1');
|
|
|
|
|
|
|
|
# Do not allow any further advancement of the restart_lsn for the lsub1_slot.
|
|
|
|
$subscriber1->safe_psql('postgres',
|
|
|
|
"ALTER SUBSCRIPTION regress_mysub1 DISABLE");
|
|
|
|
|
|
|
|
# Wait for the replication slot to become inactive on the publisher
|
|
|
|
$primary->poll_query_until(
|
|
|
|
'postgres',
|
|
|
|
"SELECT COUNT(*) FROM pg_catalog.pg_replication_slots WHERE slot_name = 'lsub1_slot' AND active = 'f'",
|
|
|
|
1);
|
|
|
|
|
|
|
|
# Wait for the standby to catch up so that the standby is not lagging behind
|
|
|
|
# the subscriber.
|
|
|
|
$primary->wait_for_replay_catchup($standby1);
|
|
|
|
|
|
|
|
# Synchronize the primary server slots to the standby.
|
|
|
|
$standby1->safe_psql('postgres', "SELECT pg_sync_replication_slots();");
|
|
|
|
|
|
|
|
# Confirm that the logical failover slots are created on the standby and are
|
|
|
|
# flagged as 'synced'
|
|
|
|
is( $standby1->safe_psql(
|
|
|
|
'postgres',
|
2024-02-14 11:46:08 +01:00
|
|
|
q{SELECT count(*) = 2 FROM pg_replication_slots WHERE slot_name IN ('lsub1_slot', 'lsub2_slot') AND synced AND NOT temporary;}
|
Add a slot synchronization function.
This commit introduces a new SQL function pg_sync_replication_slots()
which is used to synchronize the logical replication slots from the
primary server to the physical standby so that logical replication can be
resumed after a failover or planned switchover.
A new 'synced' flag is introduced in pg_replication_slots view, indicating
whether the slot has been synchronized from the primary server. On a
standby, synced slots cannot be dropped or consumed, and any attempt to
perform logical decoding on them will result in an error.
The logical replication slots on the primary can be synchronized to the
hot standby by using the 'failover' parameter of
pg-create-logical-replication-slot(), or by using the 'failover' option of
CREATE SUBSCRIPTION during slot creation, and then calling
pg_sync_replication_slots() on standby. For the synchronization to work,
it is mandatory to have a physical replication slot between the primary
and the standby aka 'primary_slot_name' should be configured on the
standby, and 'hot_standby_feedback' must be enabled on the standby. It is
also necessary to specify a valid 'dbname' in the 'primary_conninfo'.
If a logical slot is invalidated on the primary, then that slot on the
standby is also invalidated.
If a logical slot on the primary is valid but is invalidated on the
standby, then that slot is dropped but will be recreated on the standby in
the next pg_sync_replication_slots() call provided the slot still exists
on the primary server. It is okay to recreate such slots as long as these
are not consumable on standby (which is the case currently). This
situation may occur due to the following reasons:
- The 'max_slot_wal_keep_size' on the standby is insufficient to retain
WAL records from the restart_lsn of the slot.
- 'primary_slot_name' is temporarily reset to null and the physical slot
is removed.
The slot synchronization status on the standby can be monitored using the
'synced' column of pg_replication_slots view.
A functionality to automatically synchronize slots by a background worker
and allow logical walsenders to wait for the physical will be done in
subsequent commits.
Author: Hou Zhijie, Shveta Malik, Ajin Cherian based on an earlier version by Peter Eisentraut
Reviewed-by: Masahiko Sawada, Bertrand Drouvot, Peter Smith, Dilip Kumar, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-02-14 05:15:36 +01:00
|
|
|
),
|
|
|
|
"t",
|
|
|
|
'logical slots have synced as true on standby');
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# Test that the synchronized slot will be dropped if the corresponding remote
|
|
|
|
# slot on the primary server has been dropped.
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
$primary->psql('postgres', "SELECT pg_drop_replication_slot('lsub2_slot');");
|
|
|
|
|
|
|
|
$standby1->safe_psql('postgres', "SELECT pg_sync_replication_slots();");
|
|
|
|
|
|
|
|
is( $standby1->safe_psql(
|
|
|
|
'postgres',
|
|
|
|
q{SELECT count(*) = 0 FROM pg_replication_slots WHERE slot_name = 'lsub2_slot';}
|
|
|
|
),
|
|
|
|
"t",
|
|
|
|
'synchronized slot has been dropped');
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# Test that if the synchronized slot is invalidated while the remote slot is
|
|
|
|
# still valid, the slot will be dropped and re-created on the standby by
|
|
|
|
# executing pg_sync_replication_slots() again.
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
# Configure the max_slot_wal_keep_size so that the synced slot can be
|
|
|
|
# invalidated due to wal removal.
|
|
|
|
$standby1->append_conf('postgresql.conf', 'max_slot_wal_keep_size = 64kB');
|
|
|
|
$standby1->reload;
|
|
|
|
|
|
|
|
# Generate some activity and switch WAL file on the primary
|
|
|
|
$primary->advance_wal(1);
|
|
|
|
$primary->psql('postgres', "CHECKPOINT");
|
|
|
|
$primary->wait_for_replay_catchup($standby1);
|
|
|
|
|
|
|
|
# Request a checkpoint on the standby to trigger the WAL file(s) removal
|
|
|
|
$standby1->safe_psql('postgres', "CHECKPOINT");
|
|
|
|
|
|
|
|
# Check if the synced slot is invalidated
|
|
|
|
is( $standby1->safe_psql(
|
|
|
|
'postgres',
|
|
|
|
q{SELECT conflict_reason = 'wal_removed' FROM pg_replication_slots WHERE slot_name = 'lsub1_slot';}
|
|
|
|
),
|
|
|
|
"t",
|
|
|
|
'synchronized slot has been invalidated');
|
|
|
|
|
|
|
|
# Reset max_slot_wal_keep_size to avoid further wal removal
|
|
|
|
$standby1->append_conf('postgresql.conf', 'max_slot_wal_keep_size = -1');
|
|
|
|
$standby1->reload;
|
|
|
|
|
2024-02-15 06:07:28 +01:00
|
|
|
# To ensure that restart_lsn has moved to a recent WAL position, we re-create
|
|
|
|
# the subscription and the logical slot.
|
|
|
|
$subscriber1->safe_psql(
|
|
|
|
'postgres', qq[
|
|
|
|
DROP SUBSCRIPTION regress_mysub1;
|
|
|
|
CREATE SUBSCRIPTION regress_mysub1 CONNECTION '$publisher_connstr' PUBLICATION regress_mypub WITH (slot_name = lsub1_slot, copy_data = false, failover = true);
|
|
|
|
]);
|
Add a slot synchronization function.
This commit introduces a new SQL function pg_sync_replication_slots()
which is used to synchronize the logical replication slots from the
primary server to the physical standby so that logical replication can be
resumed after a failover or planned switchover.
A new 'synced' flag is introduced in pg_replication_slots view, indicating
whether the slot has been synchronized from the primary server. On a
standby, synced slots cannot be dropped or consumed, and any attempt to
perform logical decoding on them will result in an error.
The logical replication slots on the primary can be synchronized to the
hot standby by using the 'failover' parameter of
pg-create-logical-replication-slot(), or by using the 'failover' option of
CREATE SUBSCRIPTION during slot creation, and then calling
pg_sync_replication_slots() on standby. For the synchronization to work,
it is mandatory to have a physical replication slot between the primary
and the standby aka 'primary_slot_name' should be configured on the
standby, and 'hot_standby_feedback' must be enabled on the standby. It is
also necessary to specify a valid 'dbname' in the 'primary_conninfo'.
If a logical slot is invalidated on the primary, then that slot on the
standby is also invalidated.
If a logical slot on the primary is valid but is invalidated on the
standby, then that slot is dropped but will be recreated on the standby in
the next pg_sync_replication_slots() call provided the slot still exists
on the primary server. It is okay to recreate such slots as long as these
are not consumable on standby (which is the case currently). This
situation may occur due to the following reasons:
- The 'max_slot_wal_keep_size' on the standby is insufficient to retain
WAL records from the restart_lsn of the slot.
- 'primary_slot_name' is temporarily reset to null and the physical slot
is removed.
The slot synchronization status on the standby can be monitored using the
'synced' column of pg_replication_slots view.
A functionality to automatically synchronize slots by a background worker
and allow logical walsenders to wait for the physical will be done in
subsequent commits.
Author: Hou Zhijie, Shveta Malik, Ajin Cherian based on an earlier version by Peter Eisentraut
Reviewed-by: Masahiko Sawada, Bertrand Drouvot, Peter Smith, Dilip Kumar, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-02-14 05:15:36 +01:00
|
|
|
|
|
|
|
$primary->wait_for_catchup('regress_mysub1');
|
|
|
|
|
|
|
|
# Do not allow any further advancement of the restart_lsn for the lsub1_slot.
|
|
|
|
$subscriber1->safe_psql('postgres',
|
|
|
|
"ALTER SUBSCRIPTION regress_mysub1 DISABLE");
|
|
|
|
|
|
|
|
# Wait for the replication slot to become inactive on the publisher
|
|
|
|
$primary->poll_query_until(
|
|
|
|
'postgres',
|
|
|
|
"SELECT COUNT(*) FROM pg_catalog.pg_replication_slots WHERE slot_name = 'lsub1_slot' AND active = 'f'",
|
|
|
|
1);
|
|
|
|
|
|
|
|
# Wait for the standby to catch up so that the standby is not lagging behind
|
|
|
|
# the subscriber.
|
|
|
|
$primary->wait_for_replay_catchup($standby1);
|
|
|
|
|
|
|
|
my $log_offset = -s $standby1->logfile;
|
|
|
|
|
|
|
|
# Synchronize the primary server slots to the standby.
|
|
|
|
$standby1->safe_psql('postgres', "SELECT pg_sync_replication_slots();");
|
|
|
|
|
|
|
|
# Confirm that the invalidated slot has been dropped.
|
|
|
|
$standby1->wait_for_log(qr/dropped replication slot "lsub1_slot" of dbid [0-9]+/,
|
|
|
|
$log_offset);
|
|
|
|
|
|
|
|
# Confirm that the logical slot has been re-created on the standby and is
|
|
|
|
# flagged as 'synced'
|
|
|
|
is( $standby1->safe_psql(
|
|
|
|
'postgres',
|
2024-02-14 11:46:08 +01:00
|
|
|
q{SELECT conflict_reason IS NULL AND synced AND NOT temporary FROM pg_replication_slots WHERE slot_name = 'lsub1_slot';}
|
Add a slot synchronization function.
This commit introduces a new SQL function pg_sync_replication_slots()
which is used to synchronize the logical replication slots from the
primary server to the physical standby so that logical replication can be
resumed after a failover or planned switchover.
A new 'synced' flag is introduced in pg_replication_slots view, indicating
whether the slot has been synchronized from the primary server. On a
standby, synced slots cannot be dropped or consumed, and any attempt to
perform logical decoding on them will result in an error.
The logical replication slots on the primary can be synchronized to the
hot standby by using the 'failover' parameter of
pg-create-logical-replication-slot(), or by using the 'failover' option of
CREATE SUBSCRIPTION during slot creation, and then calling
pg_sync_replication_slots() on standby. For the synchronization to work,
it is mandatory to have a physical replication slot between the primary
and the standby aka 'primary_slot_name' should be configured on the
standby, and 'hot_standby_feedback' must be enabled on the standby. It is
also necessary to specify a valid 'dbname' in the 'primary_conninfo'.
If a logical slot is invalidated on the primary, then that slot on the
standby is also invalidated.
If a logical slot on the primary is valid but is invalidated on the
standby, then that slot is dropped but will be recreated on the standby in
the next pg_sync_replication_slots() call provided the slot still exists
on the primary server. It is okay to recreate such slots as long as these
are not consumable on standby (which is the case currently). This
situation may occur due to the following reasons:
- The 'max_slot_wal_keep_size' on the standby is insufficient to retain
WAL records from the restart_lsn of the slot.
- 'primary_slot_name' is temporarily reset to null and the physical slot
is removed.
The slot synchronization status on the standby can be monitored using the
'synced' column of pg_replication_slots view.
A functionality to automatically synchronize slots by a background worker
and allow logical walsenders to wait for the physical will be done in
subsequent commits.
Author: Hou Zhijie, Shveta Malik, Ajin Cherian based on an earlier version by Peter Eisentraut
Reviewed-by: Masahiko Sawada, Bertrand Drouvot, Peter Smith, Dilip Kumar, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-02-14 05:15:36 +01:00
|
|
|
),
|
|
|
|
"t",
|
|
|
|
'logical slot is re-synced');
|
|
|
|
|
2024-02-16 05:43:51 +01:00
|
|
|
# Reset the log_min_messages to the default value.
|
|
|
|
$primary->append_conf('postgresql.conf', "log_min_messages = 'warning'");
|
|
|
|
$primary->reload;
|
|
|
|
|
|
|
|
$standby1->append_conf('postgresql.conf', "log_min_messages = 'warning'");
|
|
|
|
$standby1->reload;
|
|
|
|
|
Add a slot synchronization function.
This commit introduces a new SQL function pg_sync_replication_slots()
which is used to synchronize the logical replication slots from the
primary server to the physical standby so that logical replication can be
resumed after a failover or planned switchover.
A new 'synced' flag is introduced in pg_replication_slots view, indicating
whether the slot has been synchronized from the primary server. On a
standby, synced slots cannot be dropped or consumed, and any attempt to
perform logical decoding on them will result in an error.
The logical replication slots on the primary can be synchronized to the
hot standby by using the 'failover' parameter of
pg-create-logical-replication-slot(), or by using the 'failover' option of
CREATE SUBSCRIPTION during slot creation, and then calling
pg_sync_replication_slots() on standby. For the synchronization to work,
it is mandatory to have a physical replication slot between the primary
and the standby aka 'primary_slot_name' should be configured on the
standby, and 'hot_standby_feedback' must be enabled on the standby. It is
also necessary to specify a valid 'dbname' in the 'primary_conninfo'.
If a logical slot is invalidated on the primary, then that slot on the
standby is also invalidated.
If a logical slot on the primary is valid but is invalidated on the
standby, then that slot is dropped but will be recreated on the standby in
the next pg_sync_replication_slots() call provided the slot still exists
on the primary server. It is okay to recreate such slots as long as these
are not consumable on standby (which is the case currently). This
situation may occur due to the following reasons:
- The 'max_slot_wal_keep_size' on the standby is insufficient to retain
WAL records from the restart_lsn of the slot.
- 'primary_slot_name' is temporarily reset to null and the physical slot
is removed.
The slot synchronization status on the standby can be monitored using the
'synced' column of pg_replication_slots view.
A functionality to automatically synchronize slots by a background worker
and allow logical walsenders to wait for the physical will be done in
subsequent commits.
Author: Hou Zhijie, Shveta Malik, Ajin Cherian based on an earlier version by Peter Eisentraut
Reviewed-by: Masahiko Sawada, Bertrand Drouvot, Peter Smith, Dilip Kumar, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-02-14 05:15:36 +01:00
|
|
|
##################################################
|
|
|
|
# Test that a synchronized slot can not be decoded, altered or dropped by the
|
|
|
|
# user
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
# Attempting to perform logical decoding on a synced slot should result in an error
|
|
|
|
($result, $stdout, $stderr) = $standby1->psql('postgres',
|
|
|
|
"select * from pg_logical_slot_get_changes('lsub1_slot', NULL, NULL);");
|
|
|
|
ok( $stderr =~
|
|
|
|
/ERROR: cannot use replication slot "lsub1_slot" for logical decoding/,
|
|
|
|
"logical decoding is not allowed on synced slot");
|
|
|
|
|
|
|
|
# Attempting to alter a synced slot should result in an error
|
|
|
|
($result, $stdout, $stderr) = $standby1->psql(
|
|
|
|
'postgres',
|
|
|
|
qq[ALTER_REPLICATION_SLOT lsub1_slot (failover);],
|
|
|
|
replication => 'database');
|
|
|
|
ok($stderr =~ /ERROR: cannot alter replication slot "lsub1_slot"/,
|
|
|
|
"synced slot on standby cannot be altered");
|
|
|
|
|
|
|
|
# Attempting to drop a synced slot should result in an error
|
|
|
|
($result, $stdout, $stderr) = $standby1->psql('postgres',
|
|
|
|
"SELECT pg_drop_replication_slot('lsub1_slot');");
|
|
|
|
ok($stderr =~ /ERROR: cannot drop replication slot "lsub1_slot"/,
|
|
|
|
"synced slot on standby cannot be dropped");
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# Test that we cannot synchronize slots if dbname is not specified in the
|
|
|
|
# primary_conninfo.
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
$standby1->append_conf('postgresql.conf', "primary_conninfo = '$connstr_1'");
|
|
|
|
$standby1->reload;
|
|
|
|
|
|
|
|
($result, $stdout, $stderr) =
|
|
|
|
$standby1->psql('postgres', "SELECT pg_sync_replication_slots();");
|
|
|
|
ok( $stderr =~
|
2024-02-22 06:47:00 +01:00
|
|
|
/ERROR: slot synchronization requires dbname to be specified in primary_conninfo/,
|
Add a slot synchronization function.
This commit introduces a new SQL function pg_sync_replication_slots()
which is used to synchronize the logical replication slots from the
primary server to the physical standby so that logical replication can be
resumed after a failover or planned switchover.
A new 'synced' flag is introduced in pg_replication_slots view, indicating
whether the slot has been synchronized from the primary server. On a
standby, synced slots cannot be dropped or consumed, and any attempt to
perform logical decoding on them will result in an error.
The logical replication slots on the primary can be synchronized to the
hot standby by using the 'failover' parameter of
pg-create-logical-replication-slot(), or by using the 'failover' option of
CREATE SUBSCRIPTION during slot creation, and then calling
pg_sync_replication_slots() on standby. For the synchronization to work,
it is mandatory to have a physical replication slot between the primary
and the standby aka 'primary_slot_name' should be configured on the
standby, and 'hot_standby_feedback' must be enabled on the standby. It is
also necessary to specify a valid 'dbname' in the 'primary_conninfo'.
If a logical slot is invalidated on the primary, then that slot on the
standby is also invalidated.
If a logical slot on the primary is valid but is invalidated on the
standby, then that slot is dropped but will be recreated on the standby in
the next pg_sync_replication_slots() call provided the slot still exists
on the primary server. It is okay to recreate such slots as long as these
are not consumable on standby (which is the case currently). This
situation may occur due to the following reasons:
- The 'max_slot_wal_keep_size' on the standby is insufficient to retain
WAL records from the restart_lsn of the slot.
- 'primary_slot_name' is temporarily reset to null and the physical slot
is removed.
The slot synchronization status on the standby can be monitored using the
'synced' column of pg_replication_slots view.
A functionality to automatically synchronize slots by a background worker
and allow logical walsenders to wait for the physical will be done in
subsequent commits.
Author: Hou Zhijie, Shveta Malik, Ajin Cherian based on an earlier version by Peter Eisentraut
Reviewed-by: Masahiko Sawada, Bertrand Drouvot, Peter Smith, Dilip Kumar, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-02-14 05:15:36 +01:00
|
|
|
"cannot sync slots if dbname is not specified in primary_conninfo");
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# Test that we cannot synchronize slots to a cascading standby server.
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
# Create a cascading standby
|
|
|
|
$backup_name = 'backup2';
|
|
|
|
$standby1->backup($backup_name);
|
|
|
|
|
|
|
|
my $cascading_standby = PostgreSQL::Test::Cluster->new('cascading_standby');
|
|
|
|
$cascading_standby->init_from_backup(
|
|
|
|
$standby1, $backup_name,
|
|
|
|
has_streaming => 1,
|
|
|
|
has_restoring => 1);
|
|
|
|
|
|
|
|
my $cascading_connstr = $standby1->connstr;
|
|
|
|
$cascading_standby->append_conf(
|
|
|
|
'postgresql.conf', qq(
|
|
|
|
hot_standby_feedback = on
|
|
|
|
primary_slot_name = 'cascading_sb_slot'
|
|
|
|
primary_conninfo = '$cascading_connstr dbname=postgres'
|
|
|
|
));
|
|
|
|
|
|
|
|
$standby1->psql('postgres',
|
|
|
|
q{SELECT pg_create_physical_replication_slot('cascading_sb_slot');});
|
|
|
|
|
|
|
|
$cascading_standby->start;
|
|
|
|
|
|
|
|
($result, $stdout, $stderr) =
|
|
|
|
$cascading_standby->psql('postgres', "SELECT pg_sync_replication_slots();");
|
|
|
|
ok( $stderr =~
|
|
|
|
/ERROR: cannot synchronize replication slots from a standby server/,
|
|
|
|
"cannot sync slots to a cascading standby server");
|
|
|
|
|
Add a failover option to subscriptions.
This commit introduces a new subscription option named 'failover', which
provides users with the ability to set the failover property of the
replication slot on the publisher when creating or altering a
subscription.
This uses the replication commands introduced by commit 7329240437 to
enable the failover option for a logical replication slot.
If the failover option is set to true, the associated replication slots
(i.e. the main slot and the table sync slots) in the upstream database are
enabled to be synchronized to the standbys. Note that the capability to
sync the replication slots will be added in subsequent commits.
Thanks to Masahiko Sawada for the design inputs.
Author: Shveta Malik, Hou Zhijie, Ajin Cherian
Reviewed-by: Peter Smith, Bertrand Drouvot, Dilip Kumar, Masahiko Sawada, Nisha Moond, Kuroda Hayato, Amit Kapila
Discussion: https://postgr.es/m/514f6f2f-6833-4539-39f1-96cd1e011f23@enterprisedb.com
2024-01-30 12:01:09 +01:00
|
|
|
done_testing();
|