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

Commit247c76a

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 parente4828e9 commit247c76a

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
@@ -4794,6 +4794,83 @@ compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
47944794
*result_xmax=new_xmax;
47954795
}
47964796

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

47984875
/*
47994876
* Recursive part of heap_lock_updated_tuple
@@ -4811,7 +4888,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
48114888
Bufferbuf;
48124889
uint16new_infomask,
48134890
new_infomask2,
4814-
old_infomask;
4891+
old_infomask,
4892+
old_infomask2;
48154893
TransactionIdxmax,
48164894
new_xmax;
48174895
TransactionIdpriorXmax=InvalidTransactionId;
@@ -4853,45 +4931,107 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
48534931
}
48544932

48554933
old_infomask=mytup.t_data->t_infomask;
4934+
old_infomask2=mytup.t_data->t_infomask2;
48564935
xmax=HeapTupleHeaderGetRawXmax(mytup.t_data);
48574936

48584937
/*
4859-
* If this tuple is updated and the key has been modified (or
4860-
* deleted), what we do depends on the status of the updating
4861-
* transaction: if it's live, we sleep until it finishes; if it has
4862-
* committed, we have to fail (i.e. return HeapTupleUpdated); if it
4863-
* aborted, we ignore it. For updates that didn't touch the key, we
4864-
* can just plough ahead.
4938+
* If this tuple version has been updated or locked by some concurrent
4939+
* transaction(s), what we do depends on whether our lock mode
4940+
* conflicts with what those other transactions hold, and also on the
4941+
* status of them.
48654942
*/
4866-
if (!(old_infomask&HEAP_XMAX_INVALID)&&
4867-
(mytup.t_data->t_infomask2&HEAP_KEYS_UPDATED))
4943+
if (!(old_infomask&HEAP_XMAX_INVALID))
48684944
{
4869-
TransactionIdupdate_xid;
4945+
TransactionIdrawxmax;
4946+
boolneedwait;
48704947

4871-
/*
4872-
* Note: we *must* check TransactionIdIsInProgress before
4873-
* TransactionIdDidAbort/Commit; see comment at top of tqual.c for
4874-
* an explanation.
4875-
*/
4876-
update_xid=HeapTupleHeaderGetUpdateXid(mytup.t_data);
4877-
if (TransactionIdIsCurrentTransactionId(update_xid))
4948+
rawxmax=HeapTupleHeaderGetRawXmax(mytup.t_data);
4949+
if (old_infomask&HEAP_XMAX_IS_MULTI)
48784950
{
4879-
UnlockReleaseBuffer(buf);
4880-
returnHeapTupleSelfUpdated;
4881-
}
4882-
elseif (TransactionIdIsInProgress(update_xid))
4883-
{
4884-
LockBuffer(buf,BUFFER_LOCK_UNLOCK);
4885-
/* No LockTupleTuplock here -- see heap_lock_updated_tuple */
4886-
XactLockTableWait(update_xid);
4887-
gotol4;
4951+
intnmembers;
4952+
inti;
4953+
MultiXactMember*members;
4954+
4955+
nmembers=GetMultiXactIdMembers(rawxmax,&members, false, false);
4956+
for (i=0;i<nmembers;i++)
4957+
{
4958+
HTSU_Resultres;
4959+
4960+
res=test_lockmode_for_conflict(members[i].status,
4961+
members[i].xid,
4962+
mode,&needwait);
4963+
4964+
if (needwait)
4965+
{
4966+
LockBuffer(buf,BUFFER_LOCK_UNLOCK);
4967+
XactLockTableWait(members[i].xid);
4968+
pfree(members);
4969+
gotol4;
4970+
}
4971+
if (res!=HeapTupleMayBeUpdated)
4972+
{
4973+
UnlockReleaseBuffer(buf);
4974+
pfree(members);
4975+
returnres;
4976+
}
4977+
}
4978+
if (members)
4979+
pfree(members);
48884980
}
4889-
elseif (TransactionIdDidAbort(update_xid))
4890-
;/* okay to proceed */
4891-
elseif (TransactionIdDidCommit(update_xid))
4981+
else
48924982
{
4893-
UnlockReleaseBuffer(buf);
4894-
returnHeapTupleUpdated;
4983+
HTSU_Resultres;
4984+
MultiXactStatusstatus;
4985+
4986+
/*
4987+
* For a non-multi Xmax, we first need to compute the
4988+
* corresponding MultiXactStatus by using the infomask bits.
4989+
*/
4990+
if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask))
4991+
{
4992+
if (HEAP_XMAX_IS_KEYSHR_LOCKED(old_infomask))
4993+
status=MultiXactStatusForKeyShare;
4994+
elseif (HEAP_XMAX_IS_SHR_LOCKED(old_infomask))
4995+
status=MultiXactStatusForShare;
4996+
elseif (HEAP_XMAX_IS_EXCL_LOCKED(old_infomask))
4997+
{
4998+
if (old_infomask2&HEAP_KEYS_UPDATED)
4999+
status=MultiXactStatusForUpdate;
5000+
else
5001+
status=MultiXactStatusForNoKeyUpdate;
5002+
}
5003+
else
5004+
{
5005+
/*
5006+
* LOCK_ONLY present alone (a pg_upgraded tuple
5007+
* marked as share-locked in the old cluster) shouldn't
5008+
* be seen in the middle of an update chain.
5009+
*/
5010+
elog(ERROR,"invalid lock status in tuple");
5011+
}
5012+
}
5013+
else
5014+
{
5015+
/* it's an update, but which kind? */
5016+
if (old_infomask2&HEAP_KEYS_UPDATED)
5017+
status=MultiXactStatusUpdate;
5018+
else
5019+
status=MultiXactStatusNoKeyUpdate;
5020+
}
5021+
5022+
res=test_lockmode_for_conflict(status,rawxmax,mode,
5023+
&needwait);
5024+
if (needwait)
5025+
{
5026+
LockBuffer(buf,BUFFER_LOCK_UNLOCK);
5027+
XactLockTableWait(rawxmax);
5028+
gotol4;
5029+
}
5030+
if (res!=HeapTupleMayBeUpdated)
5031+
{
5032+
UnlockReleaseBuffer(buf);
5033+
returnres;
5034+
}
48955035
}
48965036
}
48975037

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp