mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
When creating and initializing a logical slot, the restart_lsn is set to the latest WAL insertion point (or the latest replay point on standbys). Subsequently, WAL records are decoded from that point to find the start point for extracting changes in the DecodingContextFindStartpoint() function. Since the initial restart_lsn could be in the middle of a transaction, the start point must be a consistent point where we won't see the data for partial transactions. Previously, when not building a full snapshot, serialized snapshots were restored, and the SnapBuild jumps to the consistent state even while finding the start point. Consequently, the slot's restart_lsn and confirmed_flush could be set to the middle of a transaction. This could lead to various unexpected consequences. Specifically, there were reports of logical decoding decoding partial transactions, and assertion failures occurred because only subtransactions were decoded without decoding their top-level transaction until decoding the commit record. To resolve this issue, the changes prevent restoring the serialized snapshot and jumping to the consistent state while finding the start point. On v17 and HEAD, a flag indicating whether snapshot restores should be skipped has been added to the SnapBuild struct, and SNAPBUILD_VERSION has been bumpded. On backbranches, the flag is stored in the LogicalDecodingContext instead, preserving on-disk compatibility. Backpatch to all supported versions. Reported-by: Drew Callahan Reviewed-by: Amit Kapila, Hayato Kuroda Discussion: https://postgr.es/m/2444AA15-D21B-4CCE-8052-52C7C2DAFE5C%40amazon.com Backpatch-through: 12
46 lines
1.4 KiB
Plaintext
46 lines
1.4 KiB
Plaintext
Parsed test spec with 3 sessions
|
|
|
|
starting permutation: s0_init s0_begin s0_insert1 s1_init s2_checkpoint s2_get_changes_slot0 s0_insert2 s0_commit s1_get_changes_slot0 s1_get_changes_slot1
|
|
step s0_init: SELECT 'init' FROM pg_create_logical_replication_slot('slot0', 'test_decoding');
|
|
?column?
|
|
--------
|
|
init
|
|
(1 row)
|
|
|
|
step s0_begin: BEGIN;
|
|
step s0_insert1: INSERT INTO tbl VALUES (1);
|
|
step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('slot1', 'test_decoding'); <waiting ...>
|
|
step s2_checkpoint: CHECKPOINT;
|
|
step s2_get_changes_slot0: SELECT data FROM pg_logical_slot_get_changes('slot0', NULL, NULL, 'skip-empty-xacts', '1', 'include-xids', '0');
|
|
data
|
|
----
|
|
(0 rows)
|
|
|
|
step s0_insert2: INSERT INTO tbl VALUES (2);
|
|
step s0_commit: COMMIT;
|
|
step s1_init: <... completed>
|
|
?column?
|
|
--------
|
|
init
|
|
(1 row)
|
|
|
|
step s1_get_changes_slot0: SELECT data FROM pg_logical_slot_get_changes('slot0', NULL, NULL, 'skip-empty-xacts', '1', 'include-xids', '0');
|
|
data
|
|
-----------------------------------------
|
|
BEGIN
|
|
table public.tbl: INSERT: val1[integer]:1
|
|
table public.tbl: INSERT: val1[integer]:2
|
|
COMMIT
|
|
(4 rows)
|
|
|
|
step s1_get_changes_slot1: SELECT data FROM pg_logical_slot_get_changes('slot1', NULL, NULL, 'skip-empty-xacts', '1', 'include-xids', '0');
|
|
data
|
|
----
|
|
(0 rows)
|
|
|
|
?column?
|
|
--------
|
|
stop
|
|
(1 row)
|
|
|