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 (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to