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

Commit13aa624

Browse files
committed
Optimize updating a row that's locked by same xid
Updating or locking a row that was already locked by the sametransaction under the same Xid caused a MultiXact to be created; butthis is unnecessary, because there's no usefulness in being able todifferentiate two locks by the same transaction. In particular, if atransaction executed SELECT FOR UPDATE followed by an UPDATE that didn'tmodify columns of the key, we would dutifully represent the resultingcombination as a multixact -- even though a single key-update issufficient.Optimize the case so that only the strongest of both locks/updates isrepresented in Xmax. This can save some Xmax's from becomingMultiXacts, which can be a significant optimization.This missed optimization opportunity was spotted by Andres Freund whileinvestigating a bug reported by Oliver Seemann in messageCANCipfpfzoYnOz5jj=UZ70_R=CwDHv36dqWSpwsi27vpm1z5sA@mail.gmail.comand also directly as a performance regression reported by Dong Ye inmessaged54b8387.000012d8.00000010@YED-DEVD1.vmware.comReportedly, this patch fixes the performance regression.Since the missing optimization was reported as a significant performanceregression from 9.2, backpatch to 9.3.Andres Freund, tweaked by Álvaro Herrera
1 parent084e385 commit13aa624

File tree

1 file changed

+39
-31
lines changed

1 file changed

+39
-31
lines changed

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

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4705,13 +4705,20 @@ compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
47054705
uint16new_infomask,
47064706
new_infomask2;
47074707

4708+
Assert(TransactionIdIsCurrentTransactionId(add_to_xmax));
4709+
47084710
l5:
47094711
new_infomask=0;
47104712
new_infomask2=0;
47114713
if (old_infomask&HEAP_XMAX_INVALID)
47124714
{
47134715
/*
47144716
* No previous locker; we just insert our own TransactionId.
4717+
*
4718+
* Note that it's critical that this case be the first one checked,
4719+
* because there are several blocks below that come back to this one
4720+
* to implement certain optimizations; old_infomask might contain
4721+
* other dirty bits in those cases, but we don't really care.
47154722
*/
47164723
if (is_update)
47174724
{
@@ -4837,21 +4844,22 @@ compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
48374844
* create a new MultiXactId that includes both the old locker or
48384845
* updater and our own TransactionId.
48394846
*/
4840-
MultiXactStatusstatus;
48414847
MultiXactStatusnew_status;
4848+
MultiXactStatusold_status;
4849+
LockTupleModeold_mode;
48424850

48434851
if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask))
48444852
{
48454853
if (HEAP_XMAX_IS_KEYSHR_LOCKED(old_infomask))
4846-
status=MultiXactStatusForKeyShare;
4854+
old_status=MultiXactStatusForKeyShare;
48474855
elseif (HEAP_XMAX_IS_SHR_LOCKED(old_infomask))
4848-
status=MultiXactStatusForShare;
4856+
old_status=MultiXactStatusForShare;
48494857
elseif (HEAP_XMAX_IS_EXCL_LOCKED(old_infomask))
48504858
{
48514859
if (old_infomask2&HEAP_KEYS_UPDATED)
4852-
status=MultiXactStatusForUpdate;
4860+
old_status=MultiXactStatusForUpdate;
48534861
else
4854-
status=MultiXactStatusForNoKeyUpdate;
4862+
old_status=MultiXactStatusForNoKeyUpdate;
48554863
}
48564864
else
48574865
{
@@ -4871,43 +4879,43 @@ compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
48714879
{
48724880
/* it's an update, but which kind? */
48734881
if (old_infomask2&HEAP_KEYS_UPDATED)
4874-
status=MultiXactStatusUpdate;
4882+
old_status=MultiXactStatusUpdate;
48754883
else
4876-
status=MultiXactStatusNoKeyUpdate;
4884+
old_status=MultiXactStatusNoKeyUpdate;
48774885
}
48784886

4879-
new_status=get_mxact_status_for_lock(mode,is_update);
4887+
old_mode=TUPLOCK_from_mxstatus(old_status);
48804888

48814889
/*
4882-
* If theexistinglockmodeisidentical to or weaker than the new
4883-
*one, we can act as thoughthere is no existing lock, so set
4884-
*XMAX_INVALID and restart.
4890+
* If the lockto be acquiredisfor the same TransactionId as the
4891+
*existing lock,there's an optimization possible: consider only the
4892+
*strongest of both locks as the only one present, and restart.
48854893
*/
48864894
if (xmax==add_to_xmax)
48874895
{
4888-
LockTupleModeold_mode=TUPLOCK_from_mxstatus(status);
4889-
boolold_isupd=ISUPDATE_from_mxstatus(status);
4890-
48914896
/*
4892-
* We can do this if the new LockTupleMode is higher or equal than
4893-
* the old one; and if there was previously an update, we need an
4894-
* update, but if there wasn't, then we can accept there not being
4895-
* one.
4897+
* Note that it's not possible for the original tuple to be updated:
4898+
* we wouldn't be here because the tuple would have been invisible and
4899+
* we wouldn't try to update it. As a subtlety, this code can also
4900+
* run when traversing an update chain to lock future versions of a
4901+
* tuple. But we wouldn't be here either, because the add_to_xmax
4902+
* would be different from the original updater.
48964903
*/
4897-
if ((mode >=old_mode)&& (is_update|| !old_isupd))
4898-
{
4899-
/*
4900-
* Note that the infomask might contain some other dirty bits.
4901-
* However, since the new infomask is reset to zero, we only
4902-
* set what's minimally necessary, and that the case that
4903-
* checks HEAP_XMAX_INVALID is the very first above, there is
4904-
* no need for extra cleanup of the infomask here.
4905-
*/
4906-
old_infomask |=HEAP_XMAX_INVALID;
4907-
gotol5;
4908-
}
4904+
Assert(HEAP_XMAX_IS_LOCKED_ONLY(old_infomask));
4905+
4906+
/* acquire the strongest of both */
4907+
if (mode<old_mode)
4908+
mode=old_mode;
4909+
/* mustn't touch is_update */
4910+
4911+
old_infomask |=HEAP_XMAX_INVALID;
4912+
gotol5;
49094913
}
4910-
new_xmax=MultiXactIdCreate(xmax,status,add_to_xmax,new_status);
4914+
4915+
/* otherwise, just fall back to creating a new multixact */
4916+
new_status=get_mxact_status_for_lock(mode,is_update);
4917+
new_xmax=MultiXactIdCreate(xmax,old_status,
4918+
add_to_xmax,new_status);
49114919
GetMultiXactIdHintBits(new_xmax,&new_infomask,&new_infomask2);
49124920
}
49134921
elseif (!HEAP_XMAX_IS_LOCKED_ONLY(old_infomask)&&

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp