Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e3ff789

Browse files
author
Amit Kapila
committed
Stop demanding that top xact must be seen before subxact in decoding.
Manifested as ERROR: subtransaction logged without previous top-level txn record this check forbids legit behaviours like - First xl_xact_assignment record is beyond reading, i.e. earlier restart_lsn. - After restart_lsn there is some change of a subxact. - After that, there is second xl_xact_assignment (for another subxact) revealing the relationship between top and first subxact. Such a transaction won't be streamed anyway because we hadn't seen it in full. Saying for sure whether xact of some record encountered after the snapshot was deserialized can be streamed or not requires to know whether it wrote something before deserialization point --if yes, it hasn't been seen in full and can't be decoded. Snapshot doesn't have such info, so there is no easy way to relax the check. Reported-by: Hsu, John Diagnosed-by: Arseny Sher Author: Arseny Sher, Amit Kapila Reviewed-by: Amit Kapila, Dilip Kumar Backpatch-through: 9.5 Discussion: https://postgr.es/m/AB5978B2-1772-4FEE-A245-74C91704ECB0@amazon.com
1 parent fe9b928 commit e3ff789

File tree

4 files changed

+103
-4
lines changed

4 files changed

+103
-4
lines changed

contrib/test_decoding/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ REGRESS = ddl xact rewrite toast permissions decoding_in_xact \
77
decoding_into_rel binary prepared replorigin time messages \
88
spill slot truncate
99
ISOLATION = mxact delayed_startup ondisk_startup concurrent_ddl_dml \
10-
oldest_xmin snapshot_transfer
10+
oldest_xmin snapshot_transfer subxact_without_top
1111

1212
REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/test_decoding/logical.conf
1313
ISOLATION_OPTS = --temp-config $(top_srcdir)/contrib/test_decoding/logical.conf
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
Parsed test spec with 3 sessions
2+
3+
starting permutation: s0_begin s0_first_subxact s2_checkpoint s1_begin s1_dml s0_many_subxacts s0_commit s2_checkpoint s2_get_changes_suppress_output s2_get_changes_suppress_output s1_commit s2_get_changes
4+
step s0_begin: BEGIN;
5+
step s0_first_subxact:
6+
DO LANGUAGE plpgsql $$
7+
BEGIN
8+
BEGIN
9+
INSERT INTO harvest VALUES (41);
10+
EXCEPTION WHEN OTHERS THEN RAISE;
11+
END;
12+
END $$;
13+
14+
step s2_checkpoint: CHECKPOINT;
15+
step s1_begin: BEGIN;
16+
step s1_dml: INSERT INTO harvest VALUES (43);
17+
step s0_many_subxacts: select subxacts();
18+
subxacts
19+
20+
21+
step s0_commit: COMMIT;
22+
step s2_checkpoint: CHECKPOINT;
23+
step s2_get_changes_suppress_output: SELECT null n FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1') GROUP BY n;
24+
n
25+
26+
27+
step s2_get_changes_suppress_output: SELECT null n FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1') GROUP BY n;
28+
n
29+
30+
step s1_commit: COMMIT;
31+
step s2_get_changes: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
32+
data
33+
34+
BEGIN
35+
table public.harvest: INSERT: apples[integer]:43
36+
COMMIT
37+
?column?
38+
39+
stop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Test decoding of subtransactions whose top-transaction is before restart
2+
# point. Such transactions won't be streamed as we stream only complete
3+
# transactions, but it is good to test that they don't cause any problem.
4+
5+
setup
6+
{
7+
SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding'); -- must be first write in xact
8+
CREATE TABLE harvest(apples integer);
9+
CREATE OR REPLACE FUNCTION subxacts() returns void as $$
10+
BEGIN
11+
FOR i in 1 .. 128 LOOP
12+
BEGIN
13+
INSERT INTO harvest VALUES (42);
14+
EXCEPTION
15+
WHEN OTHERS THEN
16+
RAISE;
17+
END;
18+
END LOOP;
19+
END; $$LANGUAGE 'plpgsql';
20+
}
21+
22+
teardown
23+
{
24+
DROP TABLE IF EXISTS harvest;
25+
SELECT 'stop' FROM pg_drop_replication_slot('isolation_slot');
26+
}
27+
28+
session "s0"
29+
setup { SET synchronous_commit=on; }
30+
step "s0_begin" { BEGIN; }
31+
step "s0_first_subxact" {
32+
DO LANGUAGE plpgsql $$
33+
BEGIN
34+
BEGIN
35+
INSERT INTO harvest VALUES (41);
36+
EXCEPTION WHEN OTHERS THEN RAISE;
37+
END;
38+
END $$;
39+
}
40+
step "s0_many_subxacts" { select subxacts(); }
41+
step "s0_commit" { COMMIT; }
42+
43+
session "s1"
44+
setup { SET synchronous_commit=on; }
45+
step "s1_begin" { BEGIN; }
46+
step "s1_dml" { INSERT INTO harvest VALUES (43); }
47+
step "s1_commit" { COMMIT; }
48+
49+
session "s2"
50+
setup { SET synchronous_commit=on; }
51+
step "s2_checkpoint" { CHECKPOINT; }
52+
step "s2_get_changes" { SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); }
53+
step "s2_get_changes_suppress_output" { SELECT null n FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1') GROUP BY n; }
54+
55+
# The first checkpoint establishes the potential restart point (aka
56+
# restart_lsn) for the slot after the initial subxact. The second checkpoint
57+
# followed by get_changes will ensure that the potential restart point will
58+
# become the actual restart point. We do get_changes twice because if one
59+
# more xl_running_xacts record had slipped before our s0_commit, then the
60+
# potential restart point won't become actual restart point. The s1's open
61+
# transaction till get_changes holds the potential restart point to our first
62+
# checkpoint location.
63+
permutation "s0_begin" "s0_first_subxact" "s2_checkpoint" "s1_begin" "s1_dml" "s0_many_subxacts" "s0_commit" "s2_checkpoint" "s2_get_changes_suppress_output" "s2_get_changes_suppress_output" "s1_commit" "s2_get_changes"

src/backend/replication/logical/reorderbuffer.c

-3
Original file line numberDiff line numberDiff line change
@@ -838,9 +838,6 @@ ReorderBufferAssignChild(ReorderBuffer *rb, TransactionId xid,
838838
txn = ReorderBufferTXNByXid(rb, xid, true, &new_top, lsn, true);
839839
subtxn = ReorderBufferTXNByXid(rb, subxid, true, &new_sub, lsn, false);
840840

841-
if (new_top && !new_sub)
842-
elog(ERROR, "subtransaction logged without previous top-level txn record");
843-
844841
if (!new_sub)
845842
{
846843
if (rbtxn_is_known_subxact(subtxn))

0 commit comments

Comments
 (0)