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

Commit4c71f48

Browse files
committed
Use a more granular approach to follow update chains
Instead of simply checking the KEYS_UPDATED bit, we need to checkwhether each lock held on the future version of the tuple conflicts withthe lock we're trying to acquire.Per bug report #8434 by Tomonari Katsumata
1 parent2a4b6ee commit4c71f48

File tree

1 file changed

+171
-31
lines changed

1 file changed

+171
-31
lines changed

‎src/backend/access/heap/heapam.c

Lines changed: 171 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4777,6 +4777,83 @@ compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
47774777
*result_xmax=new_xmax;
47784778
}
47794779

4780+
/*
4781+
* Subroutine for heap_lock_updated_tuple_rec.
4782+
*
4783+
* Given an hypothetical multixact status held by the transaction identified
4784+
* with the given xid, does the current transaction need to wait, fail, or can
4785+
* it continue if it wanted to acquire a lock of the given mode? "needwait"
4786+
* is set to true if waiting is necessary; if it can continue, then
4787+
* HeapTupleMayBeUpdated is returned. In case of a conflict, a different
4788+
* HeapTupleSatisfiesUpdate return code is returned.
4789+
*
4790+
* The held status is said to be hypothetical because it might correspond to a
4791+
* lock held by a single Xid, i.e. not a real MultiXactId; we express it this
4792+
* way for simplicity of API.
4793+
*/
4794+
staticHTSU_Result
4795+
test_lockmode_for_conflict(MultiXactStatusstatus,TransactionIdxid,
4796+
LockTupleModemode,bool*needwait)
4797+
{
4798+
MultiXactStatuswantedstatus;
4799+
4800+
*needwait= false;
4801+
wantedstatus=get_mxact_status_for_lock(mode, false);
4802+
4803+
/*
4804+
* Note: we *must* check TransactionIdIsInProgress before
4805+
* TransactionIdDidAbort/Commit; see comment at top of tqual.c for an
4806+
* explanation.
4807+
*/
4808+
if (TransactionIdIsCurrentTransactionId(xid))
4809+
{
4810+
/*
4811+
* Updated by our own transaction? Just return failure. This shouldn't
4812+
* normally happen.
4813+
*/
4814+
returnHeapTupleSelfUpdated;
4815+
}
4816+
elseif (TransactionIdIsInProgress(xid))
4817+
{
4818+
/*
4819+
* If the locking transaction is running, what we do depends on whether
4820+
* the lock modes conflict: if they do, then we must wait for it to
4821+
* finish; otherwise we can fall through to lock this tuple version
4822+
* without waiting.
4823+
*/
4824+
if (DoLockModesConflict(LOCKMODE_from_mxstatus(status),
4825+
LOCKMODE_from_mxstatus(wantedstatus)))
4826+
{
4827+
*needwait= true;
4828+
}
4829+
4830+
/*
4831+
* If we set needwait above, then this value doesn't matter; otherwise,
4832+
* this value signals to caller that it's okay to proceed.
4833+
*/
4834+
returnHeapTupleMayBeUpdated;
4835+
}
4836+
elseif (TransactionIdDidAbort(xid))
4837+
returnHeapTupleMayBeUpdated;
4838+
elseif (TransactionIdDidCommit(xid))
4839+
{
4840+
/*
4841+
* If the updating transaction committed, what we do depends on whether
4842+
* the lock modes conflict: if they do, then we must report error to
4843+
* caller. But if they don't, we can fall through to lock it.
4844+
*/
4845+
if (DoLockModesConflict(LOCKMODE_from_mxstatus(status),
4846+
LOCKMODE_from_mxstatus(wantedstatus)))
4847+
/* bummer */
4848+
returnHeapTupleUpdated;
4849+
4850+
returnHeapTupleMayBeUpdated;
4851+
}
4852+
4853+
/* Not in progress, not aborted, not committed -- must have crashed */
4854+
returnHeapTupleMayBeUpdated;
4855+
}
4856+
47804857

47814858
/*
47824859
* Recursive part of heap_lock_updated_tuple
@@ -4794,7 +4871,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
47944871
Bufferbuf;
47954872
uint16new_infomask,
47964873
new_infomask2,
4797-
old_infomask;
4874+
old_infomask,
4875+
old_infomask2;
47984876
TransactionIdxmax,
47994877
new_xmax;
48004878
TransactionIdpriorXmax=InvalidTransactionId;
@@ -4836,45 +4914,107 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
48364914
}
48374915

48384916
old_infomask=mytup.t_data->t_infomask;
4917+
old_infomask2=mytup.t_data->t_infomask2;
48394918
xmax=HeapTupleHeaderGetRawXmax(mytup.t_data);
48404919

48414920
/*
4842-
* If this tuple is updated and the key has been modified (or
4843-
* deleted), what we do depends on the status of the updating
4844-
* transaction: if it's live, we sleep until it finishes; if it has
4845-
* committed, we have to fail (i.e. return HeapTupleUpdated); if it
4846-
* aborted, we ignore it. For updates that didn't touch the key, we
4847-
* can just plough ahead.
4921+
* If this tuple version has been updated or locked by some concurrent
4922+
* transaction(s), what we do depends on whether our lock mode
4923+
* conflicts with what those other transactions hold, and also on the
4924+
* status of them.
48484925
*/
4849-
if (!(old_infomask&HEAP_XMAX_INVALID)&&
4850-
(mytup.t_data->t_infomask2&HEAP_KEYS_UPDATED))
4926+
if (!(old_infomask&HEAP_XMAX_INVALID))
48514927
{
4852-
TransactionIdupdate_xid;
4928+
TransactionIdrawxmax;
4929+
boolneedwait;
48534930

4854-
/*
4855-
* Note: we *must* check TransactionIdIsInProgress before
4856-
* TransactionIdDidAbort/Commit; see comment at top of tqual.c for
4857-
* an explanation.
4858-
*/
4859-
update_xid=HeapTupleHeaderGetUpdateXid(mytup.t_data);
4860-
if (TransactionIdIsCurrentTransactionId(update_xid))
4931+
rawxmax=HeapTupleHeaderGetRawXmax(mytup.t_data);
4932+
if (old_infomask&HEAP_XMAX_IS_MULTI)
48614933
{
4862-
UnlockReleaseBuffer(buf);
4863-
returnHeapTupleSelfUpdated;
4864-
}
4865-
elseif (TransactionIdIsInProgress(update_xid))
4866-
{
4867-
LockBuffer(buf,BUFFER_LOCK_UNLOCK);
4868-
/* No LockTupleTuplock here -- see heap_lock_updated_tuple */
4869-
XactLockTableWait(update_xid);
4870-
gotol4;
4934+
intnmembers;
4935+
inti;
4936+
MultiXactMember*members;
4937+
4938+
nmembers=GetMultiXactIdMembers(rawxmax,&members, false);
4939+
for (i=0;i<nmembers;i++)
4940+
{
4941+
HTSU_Resultres;
4942+
4943+
res=test_lockmode_for_conflict(members[i].status,
4944+
members[i].xid,
4945+
mode,&needwait);
4946+
4947+
if (needwait)
4948+
{
4949+
LockBuffer(buf,BUFFER_LOCK_UNLOCK);
4950+
XactLockTableWait(members[i].xid);
4951+
pfree(members);
4952+
gotol4;
4953+
}
4954+
if (res!=HeapTupleMayBeUpdated)
4955+
{
4956+
UnlockReleaseBuffer(buf);
4957+
pfree(members);
4958+
returnres;
4959+
}
4960+
}
4961+
if (members)
4962+
pfree(members);
48714963
}
4872-
elseif (TransactionIdDidAbort(update_xid))
4873-
;/* okay to proceed */
4874-
elseif (TransactionIdDidCommit(update_xid))
4964+
else
48754965
{
4876-
UnlockReleaseBuffer(buf);
4877-
returnHeapTupleUpdated;
4966+
HTSU_Resultres;
4967+
MultiXactStatusstatus;
4968+
4969+
/*
4970+
* For a non-multi Xmax, we first need to compute the
4971+
* corresponding MultiXactStatus by using the infomask bits.
4972+
*/
4973+
if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask))
4974+
{
4975+
if (HEAP_XMAX_IS_KEYSHR_LOCKED(old_infomask))
4976+
status=MultiXactStatusForKeyShare;
4977+
elseif (HEAP_XMAX_IS_SHR_LOCKED(old_infomask))
4978+
status=MultiXactStatusForShare;
4979+
elseif (HEAP_XMAX_IS_EXCL_LOCKED(old_infomask))
4980+
{
4981+
if (old_infomask2&HEAP_KEYS_UPDATED)
4982+
status=MultiXactStatusForUpdate;
4983+
else
4984+
status=MultiXactStatusForNoKeyUpdate;
4985+
}
4986+
else
4987+
{
4988+
/*
4989+
* LOCK_ONLY present alone (a pg_upgraded tuple
4990+
* marked as share-locked in the old cluster) shouldn't
4991+
* be seen in the middle of an update chain.
4992+
*/
4993+
elog(ERROR,"invalid lock status in tuple");
4994+
}
4995+
}
4996+
else
4997+
{
4998+
/* it's an update, but which kind? */
4999+
if (old_infomask2&HEAP_KEYS_UPDATED)
5000+
status=MultiXactStatusUpdate;
5001+
else
5002+
status=MultiXactStatusNoKeyUpdate;
5003+
}
5004+
5005+
res=test_lockmode_for_conflict(status,rawxmax,mode,
5006+
&needwait);
5007+
if (needwait)
5008+
{
5009+
LockBuffer(buf,BUFFER_LOCK_UNLOCK);
5010+
XactLockTableWait(rawxmax);
5011+
gotol4;
5012+
}
5013+
if (res!=HeapTupleMayBeUpdated)
5014+
{
5015+
UnlockReleaseBuffer(buf);
5016+
returnres;
5017+
}
48785018
}
48795019
}
48805020

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp