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

Commit85d3b3c

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 parentdb1014b commit85d3b3c

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
@@ -4534,13 +4534,20 @@ compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
45344534
uint16new_infomask,
45354535
new_infomask2;
45364536

4537+
Assert(TransactionIdIsCurrentTransactionId(add_to_xmax));
4538+
45374539
l5:
45384540
new_infomask=0;
45394541
new_infomask2=0;
45404542
if (old_infomask&HEAP_XMAX_INVALID)
45414543
{
45424544
/*
45434545
* No previous locker; we just insert our own TransactionId.
4546+
*
4547+
* Note that it's critical that this case be the first one checked,
4548+
* because there are several blocks below that come back to this one
4549+
* to implement certain optimizations; old_infomask might contain
4550+
* other dirty bits in those cases, but we don't really care.
45444551
*/
45454552
if (is_update)
45464553
{
@@ -4666,21 +4673,22 @@ compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
46664673
* create a new MultiXactId that includes both the old locker or
46674674
* updater and our own TransactionId.
46684675
*/
4669-
MultiXactStatusstatus;
46704676
MultiXactStatusnew_status;
4677+
MultiXactStatusold_status;
4678+
LockTupleModeold_mode;
46714679

46724680
if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask))
46734681
{
46744682
if (HEAP_XMAX_IS_KEYSHR_LOCKED(old_infomask))
4675-
status=MultiXactStatusForKeyShare;
4683+
old_status=MultiXactStatusForKeyShare;
46764684
elseif (HEAP_XMAX_IS_SHR_LOCKED(old_infomask))
4677-
status=MultiXactStatusForShare;
4685+
old_status=MultiXactStatusForShare;
46784686
elseif (HEAP_XMAX_IS_EXCL_LOCKED(old_infomask))
46794687
{
46804688
if (old_infomask2&HEAP_KEYS_UPDATED)
4681-
status=MultiXactStatusForUpdate;
4689+
old_status=MultiXactStatusForUpdate;
46824690
else
4683-
status=MultiXactStatusForNoKeyUpdate;
4691+
old_status=MultiXactStatusForNoKeyUpdate;
46844692
}
46854693
else
46864694
{
@@ -4700,43 +4708,43 @@ compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
47004708
{
47014709
/* it's an update, but which kind? */
47024710
if (old_infomask2&HEAP_KEYS_UPDATED)
4703-
status=MultiXactStatusUpdate;
4711+
old_status=MultiXactStatusUpdate;
47044712
else
4705-
status=MultiXactStatusNoKeyUpdate;
4713+
old_status=MultiXactStatusNoKeyUpdate;
47064714
}
47074715

4708-
new_status=get_mxact_status_for_lock(mode,is_update);
4716+
old_mode=TUPLOCK_from_mxstatus(old_status);
47094717

47104718
/*
4711-
* If theexistinglockmodeisidentical to or weaker than the new
4712-
*one, we can act as thoughthere is no existing lock, so set
4713-
*XMAX_INVALID and restart.
4719+
* If the lockto be acquiredisfor the same TransactionId as the
4720+
*existing lock,there's an optimization possible: consider only the
4721+
*strongest of both locks as the only one present, and restart.
47144722
*/
47154723
if (xmax==add_to_xmax)
47164724
{
4717-
LockTupleModeold_mode=TUPLOCK_from_mxstatus(status);
4718-
boolold_isupd=ISUPDATE_from_mxstatus(status);
4719-
47204725
/*
4721-
* We can do this if the new LockTupleMode is higher or equal than
4722-
* the old one; and if there was previously an update, we need an
4723-
* update, but if there wasn't, then we can accept there not being
4724-
* one.
4726+
* Note that it's not possible for the original tuple to be updated:
4727+
* we wouldn't be here because the tuple would have been invisible and
4728+
* we wouldn't try to update it. As a subtlety, this code can also
4729+
* run when traversing an update chain to lock future versions of a
4730+
* tuple. But we wouldn't be here either, because the add_to_xmax
4731+
* would be different from the original updater.
47254732
*/
4726-
if ((mode >=old_mode)&& (is_update|| !old_isupd))
4727-
{
4728-
/*
4729-
* Note that the infomask might contain some other dirty bits.
4730-
* However, since the new infomask is reset to zero, we only
4731-
* set what's minimally necessary, and that the case that
4732-
* checks HEAP_XMAX_INVALID is the very first above, there is
4733-
* no need for extra cleanup of the infomask here.
4734-
*/
4735-
old_infomask |=HEAP_XMAX_INVALID;
4736-
gotol5;
4737-
}
4733+
Assert(HEAP_XMAX_IS_LOCKED_ONLY(old_infomask));
4734+
4735+
/* acquire the strongest of both */
4736+
if (mode<old_mode)
4737+
mode=old_mode;
4738+
/* mustn't touch is_update */
4739+
4740+
old_infomask |=HEAP_XMAX_INVALID;
4741+
gotol5;
47384742
}
4739-
new_xmax=MultiXactIdCreate(xmax,status,add_to_xmax,new_status);
4743+
4744+
/* otherwise, just fall back to creating a new multixact */
4745+
new_status=get_mxact_status_for_lock(mode,is_update);
4746+
new_xmax=MultiXactIdCreate(xmax,old_status,
4747+
add_to_xmax,new_status);
47404748
GetMultiXactIdHintBits(new_xmax,&new_infomask,&new_infomask2);
47414749
}
47424750
elseif (!HEAP_XMAX_IS_LOCKED_ONLY(old_infomask)&&

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp