Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite620a38

Browse files
Avoid update conflict out serialization anomalies.
SSI's HeapCheckForSerializableConflictOut() test failed to correctlyhandle conditions involving a concurrently inserted tuple which is laterconcurrently updated by a separate transaction . A SELECT statementthat called HeapCheckForSerializableConflictOut() could end up using thesame XID (updater's XID) for both the original tuple, and the successortuple, missing the XID of the xact that created the original tupleentirely. This only happened when neither tuple from the chain wasvisible to the transaction's MVCC snapshot.The observable symptoms of this bug were subtle. A pair of transactionscould commit, with the later transaction failing to observe the effectsof the earlier transaction (because of the confusion created by theupdate to the non-visible row). This bug dates all the way back tocommitdafaa3e, which added SSI.To fix, make sure that we check the xmin of concurrently inserted tuplesthat happen to also have been updated concurrently.Author: Peter GeogheganReported-By: Kyle KingsburyReviewed-By: Thomas MunroDiscussion:https://postgr.es/m/db7b729d-0226-d162-a126-8a8ab2dc4443@jepsen.ioBackpatch: All supported versions
1 parentb7ed1d9 commite620a38

File tree

4 files changed

+98
-5
lines changed

4 files changed

+98
-5
lines changed

‎src/backend/storage/lmgr/predicate.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4083,6 +4083,10 @@ CheckForSerializableConflictOut(bool visible, Relation relation,
40834083
* while it is visible to us. The "visible" bool indicates whether the
40844084
* tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
40854085
* is going on with it.
4086+
*
4087+
* In the event of a concurrently inserted tuple that also happens to have
4088+
* been concurrently updated (by a separate transaction), the xmin of the
4089+
* tuple will be used -- not the updater's xid.
40864090
*/
40874091
htsvResult=HeapTupleSatisfiesVacuum(tuple,TransactionXmin,buffer);
40884092
switch (htsvResult)
@@ -4093,17 +4097,24 @@ CheckForSerializableConflictOut(bool visible, Relation relation,
40934097
xid=HeapTupleHeaderGetXmin(tuple->t_data);
40944098
break;
40954099
caseHEAPTUPLE_RECENTLY_DEAD:
4096-
if (!visible)
4097-
return;
4098-
xid=HeapTupleHeaderGetUpdateXid(tuple->t_data);
4099-
break;
41004100
caseHEAPTUPLE_DELETE_IN_PROGRESS:
4101-
xid=HeapTupleHeaderGetUpdateXid(tuple->t_data);
4101+
if (visible)
4102+
xid=HeapTupleHeaderGetUpdateXid(tuple->t_data);
4103+
else
4104+
xid=HeapTupleHeaderGetXmin(tuple->t_data);
4105+
4106+
if (TransactionIdPrecedes(xid,TransactionXmin))
4107+
{
4108+
/* This is like the HEAPTUPLE_DEAD case */
4109+
Assert(!visible);
4110+
return;
4111+
}
41024112
break;
41034113
caseHEAPTUPLE_INSERT_IN_PROGRESS:
41044114
xid=HeapTupleHeaderGetXmin(tuple->t_data);
41054115
break;
41064116
caseHEAPTUPLE_DEAD:
4117+
Assert(!visible);
41074118
return;
41084119
default:
41094120

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Parsed test spec with 3 sessions
2+
3+
starting permutation: foo_select bar_insert foo_insert foo_commit trouble_update bar_select bar_commit trouble_abort
4+
step foo_select: SELECT * FROM txn0 WHERE id = 42;
5+
id val
6+
7+
step bar_insert: INSERT INTO txn0 SELECT 42, 'bar_insert';
8+
step foo_insert: INSERT INTO txn1 SELECT 7, 'foo_insert';
9+
step foo_commit: COMMIT;
10+
step trouble_update: UPDATE txn1 SET val = 'add physical version for "bar_select"' WHERE id = 7;
11+
step bar_select: SELECT * FROM txn1 WHERE id = 7;
12+
ERROR: could not serialize access due to read/write dependencies among transactions
13+
step bar_commit: COMMIT;
14+
step trouble_abort: ABORT;
15+
16+
starting permutation: foo_select bar_insert foo_insert foo_commit trouble_delete bar_select bar_commit trouble_abort
17+
step foo_select: SELECT * FROM txn0 WHERE id = 42;
18+
id val
19+
20+
step bar_insert: INSERT INTO txn0 SELECT 42, 'bar_insert';
21+
step foo_insert: INSERT INTO txn1 SELECT 7, 'foo_insert';
22+
step foo_commit: COMMIT;
23+
step trouble_delete: DELETE FROM txn1 WHERE id = 7;
24+
step bar_select: SELECT * FROM txn1 WHERE id = 7;
25+
ERROR: could not serialize access due to read/write dependencies among transactions
26+
step bar_commit: COMMIT;
27+
step trouble_abort: ABORT;

‎src/test/isolation/isolation_schedule

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ test: two-ids
1818
test: multiple-row-versions
1919
test: index-only-scan
2020
test: predicate-lock-hot-tuple
21+
test: update-conflict-out
2122
test: deadlock-simple
2223
test: deadlock-hard
2324
test: deadlock-soft
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Test for interactions between SSI's "conflict out" handling for heapam and
2+
# concurrently updated tuple
3+
#
4+
# See bug report:
5+
# https://postgr.es/m/db7b729d-0226-d162-a126-8a8ab2dc4443%40jepsen.io
6+
7+
setup
8+
{
9+
CREATETABLEtxn0(idint4PRIMARYKEY,valTEXT);
10+
CREATETABLEtxn1(idint4PRIMARYKEY,valTEXT);
11+
}
12+
13+
teardown
14+
{
15+
DROPTABLEtxn0;
16+
DROPTABLEtxn1;
17+
}
18+
19+
session"foo"
20+
setup {BEGINTRANSACTIONISOLATIONLEVELSERIALIZABLE; }
21+
step"foo_select" {SELECT*FROMtxn0WHEREid=42; }
22+
step"foo_insert" {INSERTINTOtxn1SELECT7,'foo_insert'; }
23+
step"foo_commit" {COMMIT; }
24+
25+
session"bar"
26+
setup {BEGINTRANSACTIONISOLATIONLEVELSERIALIZABLE; }
27+
step"bar_select" {SELECT*FROMtxn1WHEREid=7; }
28+
step"bar_insert" {INSERTINTOtxn0SELECT42,'bar_insert'; }
29+
step"bar_commit" {COMMIT; }
30+
31+
# This session creates the conditions that confused bar's "conflict out"
32+
# handling in old releases affected by bug:
33+
session"trouble"
34+
setup {BEGINTRANSACTIONISOLATIONLEVELSERIALIZABLE; }
35+
step"trouble_update" {UPDATEtxn1SETval='add physical version for "bar_select"'WHEREid=7; }
36+
step"trouble_delete" {DELETEFROMtxn1WHEREid=7; }
37+
step"trouble_abort" {ABORT; }
38+
39+
permutation"foo_select"
40+
"bar_insert"
41+
"foo_insert""foo_commit"
42+
"trouble_update"# Updates tuple...
43+
"bar_select"# Should observe one distinct XID per version
44+
"bar_commit"# "bar" should fail here at the latest
45+
"trouble_abort"
46+
47+
# Same as above, but "trouble" session DELETEs this time around
48+
permutation"foo_select"
49+
"bar_insert"
50+
"foo_insert""foo_commit"
51+
"trouble_delete"# Deletes tuple...
52+
"bar_select"# Should observe foo's XID
53+
"bar_commit"# "bar" should fail here at the latest
54+
"trouble_abort"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp