Alvaro Herrera wrote:
> Attached is a patch to fix it.
--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
*** a/src/backend/utils/time/tqual.c
--- b/src/backend/utils/time/tqual.c
***************
*** 789,801 **** HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
if (TransactionIdDidCommit(xmax))
return HeapTupleUpdated;
! /* no member, even just a locker, alive anymore */
if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple)))
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId);
!
! /* it must have aborted or crashed */
! return HeapTupleMayBeUpdated;
}
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
--- 789,814 ----
if (TransactionIdDidCommit(xmax))
return HeapTupleUpdated;
! /*
! * By here, the update in the Xmax is either aborted or crashed, but
! * what about the other members?
! */
!
if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple)))
+ {
+ /*
+ * There's no member, even just a locker, alive anymore, so we can
+ * mark the Xmax as invalid.
+ */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId);
! return HeapTupleMayBeUpdated;
! }
! else
! {
! /* There are lockers running */
! return HeapTupleBeingUpdated;
! }
}
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
*** a/src/test/isolation/expected/delete-abort-savept.out
--- b/src/test/isolation/expected/delete-abort-savept.out
***************
*** 23,33 **** key value
step s1svp: SAVEPOINT f;
step s1d: DELETE FROM foo;
step s1r: ROLLBACK TO f;
! step s2l: SELECT * FROM foo FOR UPDATE;
key value
1 1
- step s1c: COMMIT;
step s2c: COMMIT;
starting permutation: s1l s1svp s1d s1r s2l s2c s1c
--- 23,34 ----
step s1svp: SAVEPOINT f;
step s1d: DELETE FROM foo;
step s1r: ROLLBACK TO f;
! step s2l: SELECT * FROM foo FOR UPDATE; <waiting ...>
! step s1c: COMMIT;
! step s2l: <... completed>
key value
1 1
step s2c: COMMIT;
starting permutation: s1l s1svp s1d s1r s2l s2c s1c
***************
*** 38,49 **** key value
step s1svp: SAVEPOINT f;
step s1d: DELETE FROM foo;
step s1r: ROLLBACK TO f;
! step s2l: SELECT * FROM foo FOR UPDATE;
! key value
!
! 1 1
! step s2c: COMMIT;
! step s1c: COMMIT;
starting permutation: s1l s1svp s1d s2l s1r s1c s2c
step s1l: SELECT * FROM foo FOR KEY SHARE;
--- 39,46 ----
step s1svp: SAVEPOINT f;
step s1d: DELETE FROM foo;
step s1r: ROLLBACK TO f;
! step s2l: SELECT * FROM foo FOR UPDATE; <waiting ...>
! invalid permutation detected
starting permutation: s1l s1svp s1d s2l s1r s1c s2c
step s1l: SELECT * FROM foo FOR KEY SHARE;
*** /dev/null
--- b/src/test/isolation/expected/multixact-no-forget.out
***************
*** 0 ****
--- 1,28 ----
+ Parsed test spec with 3 sessions
+
+ starting permutation: s1_lock s2_update s2_abort s3_lock s1_commit
+ step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+ value
+
+ 1
+ step s2_update: UPDATE dont_forget SET value = 2;
+ step s2_abort: ROLLBACK;
+ step s3_lock: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+ step s1_commit: COMMIT;
+ step s3_lock: <... completed>
+ value
+
+
+ starting permutation: s1_lock s2_update s2_commit s3_lock s1_commit
+ step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+ value
+
+ 1
+ step s2_update: UPDATE dont_forget SET value = 2;
+ step s2_commit: COMMIT;
+ step s3_lock: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+ step s1_commit: COMMIT;
+ step s3_lock: <... completed>
+ value
+
+ 2
*** /dev/null
--- b/src/test/isolation/expected/multixact-no-forget_1.out
***************
*** 0 ****
--- 1,27 ----
+ Parsed test spec with 3 sessions
+
+ starting permutation: s1_lock s2_update s2_abort s3_lock s1_commit
+ step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+ value
+
+ 1
+ step s2_update: UPDATE dont_forget SET value = 2;
+ step s2_abort: ROLLBACK;
+ step s3_lock: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+ step s1_commit: COMMIT;
+ step s3_lock: <... completed>
+ error in steps s1_commit s3_lock: ERROR: could not serialize access due to concurrent update
+
+ starting permutation: s1_lock s2_update s2_commit s3_lock s1_commit
+ step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+ value
+
+ 1
+ step s2_update: UPDATE dont_forget SET value = 2;
+ step s2_commit: COMMIT;
+ step s3_lock: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+ step s1_commit: COMMIT;
+ step s3_lock: <... completed>
+ value
+
+ 2
*** a/src/test/isolation/isolation_schedule
--- b/src/test/isolation/isolation_schedule
***************
*** 20,24 **** test: delete-abort-savept
--- 20,25 ----
test: delete-abort-savept-2
test: aborted-keyrevoke
test: multixact-no-deadlock
+ test: multixact-no-forget
test: drop-index-concurrently-1
test: timeouts
*** /dev/null
--- b/src/test/isolation/specs/multixact-no-forget.spec
***************
*** 0 ****
--- 1,32 ----
+ # If transaction A holds a lock, and transaction B does an update,
+ # make sure we don't forget the lock if B aborts.
+ setup
+ {
+ CREATE TABLE dont_forget (
+ value int
+ );
+
+ INSERT INTO dont_forget VALUES (1);
+ }
+
+ teardown
+ {
+ DROP TABLE dont_forget;
+ }
+
+ session "s1"
+ setup { BEGIN; }
+ step "s1_lock" { SELECT * FROM dont_forget FOR KEY SHARE; }
+ step "s1_commit" { COMMIT; }
+
+ session "s2"
+ setup { BEGIN; }
+ step "s2_update" { UPDATE dont_forget SET value = 2; }
+ step "s2_abort" { ROLLBACK; }
+ step "s2_commit" { COMMIT; }
+
+ session "s3"
+ step "s3_lock" { SELECT * FROM dont_forget FOR UPDATE; }
+
+ permutation "s1_lock" "s2_update" "s2_abort" "s3_lock" "s1_commit"
+ permutation "s1_lock" "s2_update" "s2_commit" "s3_lock" "s1_commit"
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers