mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-23 06:30:39 +02:00
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
138 lines
4.1 KiB
Plaintext
138 lines
4.1 KiB
Plaintext
-- predictability
|
|
SET synchronous_commit = on;
|
|
-- setup
|
|
CREATE ROLE regress_lr_normal;
|
|
CREATE ROLE regress_lr_superuser SUPERUSER;
|
|
CREATE ROLE regress_lr_replication REPLICATION;
|
|
CREATE TABLE lr_test(data text);
|
|
-- superuser can control replication
|
|
SET ROLE regress_lr_superuser;
|
|
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
|
|
?column?
|
|
----------
|
|
init
|
|
(1 row)
|
|
|
|
INSERT INTO lr_test VALUES('lr_superuser_init');
|
|
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
|
|
data
|
|
--------------------------------------------------------------
|
|
BEGIN
|
|
table public.lr_test: INSERT: data[text]:'lr_superuser_init'
|
|
COMMIT
|
|
(3 rows)
|
|
|
|
SELECT pg_drop_replication_slot('regression_slot');
|
|
pg_drop_replication_slot
|
|
--------------------------
|
|
|
|
(1 row)
|
|
|
|
RESET ROLE;
|
|
-- replication user can control replication
|
|
SET ROLE regress_lr_replication;
|
|
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
|
|
?column?
|
|
----------
|
|
init
|
|
(1 row)
|
|
|
|
INSERT INTO lr_test VALUES('lr_superuser_init');
|
|
ERROR: permission denied for table lr_test
|
|
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
|
|
data
|
|
------
|
|
(0 rows)
|
|
|
|
SELECT pg_drop_replication_slot('regression_slot');
|
|
pg_drop_replication_slot
|
|
--------------------------
|
|
|
|
(1 row)
|
|
|
|
RESET ROLE;
|
|
-- plain user *can't* can control replication
|
|
SET ROLE regress_lr_normal;
|
|
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
|
|
ERROR: permission denied to use replication slots
|
|
DETAIL: Only roles with the REPLICATION attribute may use replication slots.
|
|
INSERT INTO lr_test VALUES('lr_superuser_init');
|
|
ERROR: permission denied for table lr_test
|
|
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
|
|
ERROR: permission denied to use replication slots
|
|
DETAIL: Only roles with the REPLICATION attribute may use replication slots.
|
|
SELECT pg_drop_replication_slot('regression_slot');
|
|
ERROR: permission denied to use replication slots
|
|
DETAIL: Only roles with the REPLICATION attribute may use replication slots.
|
|
SELECT pg_sync_replication_slots();
|
|
ERROR: permission denied to use replication slots
|
|
DETAIL: Only roles with the REPLICATION attribute may use replication slots.
|
|
RESET ROLE;
|
|
-- replication users can drop superuser created slots
|
|
SET ROLE regress_lr_superuser;
|
|
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
|
|
?column?
|
|
----------
|
|
init
|
|
(1 row)
|
|
|
|
RESET ROLE;
|
|
SET ROLE regress_lr_replication;
|
|
SELECT pg_drop_replication_slot('regression_slot');
|
|
pg_drop_replication_slot
|
|
--------------------------
|
|
|
|
(1 row)
|
|
|
|
RESET ROLE;
|
|
-- normal users can't drop existing slots
|
|
SET ROLE regress_lr_superuser;
|
|
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
|
|
?column?
|
|
----------
|
|
init
|
|
(1 row)
|
|
|
|
RESET ROLE;
|
|
SET ROLE regress_lr_normal;
|
|
SELECT pg_drop_replication_slot('regression_slot');
|
|
ERROR: permission denied to use replication slots
|
|
DETAIL: Only roles with the REPLICATION attribute may use replication slots.
|
|
RESET ROLE;
|
|
-- all users can see existing slots
|
|
SET ROLE regress_lr_superuser;
|
|
SELECT slot_name, plugin FROM pg_replication_slots;
|
|
slot_name | plugin
|
|
-----------------+---------------
|
|
regression_slot | test_decoding
|
|
(1 row)
|
|
|
|
RESET ROLE;
|
|
SET ROLE regress_lr_replication;
|
|
SELECT slot_name, plugin FROM pg_replication_slots;
|
|
slot_name | plugin
|
|
-----------------+---------------
|
|
regression_slot | test_decoding
|
|
(1 row)
|
|
|
|
RESET ROLE;
|
|
SET ROLE regress_lr_normal;
|
|
SELECT slot_name, plugin FROM pg_replication_slots;
|
|
slot_name | plugin
|
|
-----------------+---------------
|
|
regression_slot | test_decoding
|
|
(1 row)
|
|
|
|
RESET ROLE;
|
|
-- cleanup
|
|
SELECT pg_drop_replication_slot('regression_slot');
|
|
pg_drop_replication_slot
|
|
--------------------------
|
|
|
|
(1 row)
|
|
|
|
DROP ROLE regress_lr_normal;
|
|
DROP ROLE regress_lr_superuser;
|
|
DROP ROLE regress_lr_replication;
|
|
DROP TABLE lr_test;
|