@@ -105,11 +105,12 @@ static void GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask,
105
105
uint16 * new_infomask2 );
106
106
static TransactionId MultiXactIdGetUpdateXid (TransactionId xmax ,
107
107
uint16 t_infomask );
108
- static void MultiXactIdWait (MultiXactId multi , MultiXactStatus status ,
109
- int * remaining , uint16 infomask );
110
- static bool ConditionalMultiXactIdWait (MultiXactId multi ,
111
- MultiXactStatus status , int * remaining ,
112
- uint16 infomask );
108
+ static void MultiXactIdWait (MultiXactId multi , MultiXactStatus status , uint16 infomask ,
109
+ Relation rel , ItemPointer ctid , XLTW_Oper oper ,
110
+ int * remaining );
111
+ static bool ConditionalMultiXactIdWait (MultiXactId multi , MultiXactStatus status ,
112
+ uint16 infomask , Relation rel , ItemPointer ctid ,
113
+ XLTW_Oper oper , int * remaining );
113
114
static XLogRecPtr log_heap_new_cid (Relation relation , HeapTuple tup );
114
115
static HeapTuple ExtractReplicaIdentity (Relation rel , HeapTuple tup , bool key_modified ,
115
116
bool * copy );
@@ -2714,8 +2715,9 @@ heap_delete(Relation relation, ItemPointer tid,
2714
2715
if (infomask & HEAP_XMAX_IS_MULTI )
2715
2716
{
2716
2717
/* wait for multixact */
2717
- MultiXactIdWait ((MultiXactId ) xwait , MultiXactStatusUpdate ,
2718
- NULL , infomask );
2718
+ MultiXactIdWait ((MultiXactId ) xwait , MultiXactStatusUpdate , infomask ,
2719
+ relation , & tp .t_data -> t_ctid , XLTW_Delete ,
2720
+ NULL );
2719
2721
LockBuffer (buffer , BUFFER_LOCK_EXCLUSIVE );
2720
2722
2721
2723
/*
@@ -2741,7 +2743,7 @@ heap_delete(Relation relation, ItemPointer tid,
2741
2743
else
2742
2744
{
2743
2745
/* wait for regular transaction to end */
2744
- XactLockTableWait (xwait );
2746
+ XactLockTableWait (xwait , relation , & tp . t_data -> t_ctid , XLTW_Delete );
2745
2747
LockBuffer (buffer , BUFFER_LOCK_EXCLUSIVE );
2746
2748
2747
2749
/*
@@ -3266,8 +3268,9 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
3266
3268
int remain ;
3267
3269
3268
3270
/* wait for multixact */
3269
- MultiXactIdWait ((MultiXactId ) xwait , mxact_status , & remain ,
3270
- infomask );
3271
+ MultiXactIdWait ((MultiXactId ) xwait , mxact_status , infomask ,
3272
+ relation , & oldtup .t_data -> t_ctid , XLTW_Update ,
3273
+ & remain );
3271
3274
LockBuffer (buffer , BUFFER_LOCK_EXCLUSIVE );
3272
3275
3273
3276
/*
@@ -3341,7 +3344,8 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
3341
3344
else
3342
3345
{
3343
3346
/* wait for regular transaction to end */
3344
- XactLockTableWait (xwait );
3347
+ XactLockTableWait (xwait , relation , & oldtup .t_data -> t_ctid ,
3348
+ XLTW_Update );
3345
3349
LockBuffer (buffer , BUFFER_LOCK_EXCLUSIVE );
3346
3350
3347
3351
/*
@@ -4402,14 +4406,18 @@ heap_lock_tuple(Relation relation, HeapTuple tuple,
4402
4406
if (nowait )
4403
4407
{
4404
4408
if (!ConditionalMultiXactIdWait ((MultiXactId ) xwait ,
4405
- status , NULL , infomask ))
4409
+ status , infomask , relation ,
4410
+ & tuple -> t_data -> t_ctid ,
4411
+ XLTW_Lock , NULL ))
4406
4412
ereport (ERROR ,
4407
4413
(errcode (ERRCODE_LOCK_NOT_AVAILABLE ),
4408
4414
errmsg ("could not obtain lock on row in relation \"%s\"" ,
4409
4415
RelationGetRelationName (relation ))));
4410
4416
}
4411
4417
else
4412
- MultiXactIdWait ((MultiXactId ) xwait , status , NULL , infomask );
4418
+ MultiXactIdWait ((MultiXactId ) xwait , status , infomask ,
4419
+ relation , & tuple -> t_data -> t_ctid ,
4420
+ XLTW_Lock , NULL );
4413
4421
4414
4422
/* if there are updates, follow the update chain */
4415
4423
if (follow_updates &&
@@ -4464,7 +4472,8 @@ heap_lock_tuple(Relation relation, HeapTuple tuple,
4464
4472
RelationGetRelationName (relation ))));
4465
4473
}
4466
4474
else
4467
- XactLockTableWait (xwait );
4475
+ XactLockTableWait (xwait , relation , & tuple -> t_data -> t_ctid ,
4476
+ XLTW_Lock );
4468
4477
4469
4478
/* if there are updates, follow the update chain */
4470
4479
if (follow_updates &&
@@ -5151,7 +5160,9 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5151
5160
if (needwait )
5152
5161
{
5153
5162
LockBuffer (buf , BUFFER_LOCK_UNLOCK );
5154
- XactLockTableWait (members [i ].xid );
5163
+ XactLockTableWait (members [i ].xid , rel ,
5164
+ & mytup .t_data -> t_ctid ,
5165
+ XLTW_LockUpdated );
5155
5166
pfree (members );
5156
5167
goto l4 ;
5157
5168
}
@@ -5211,7 +5222,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
5211
5222
if (needwait )
5212
5223
{
5213
5224
LockBuffer (buf , BUFFER_LOCK_UNLOCK );
5214
- XactLockTableWait (rawxmax );
5225
+ XactLockTableWait (rawxmax , rel , & mytup .t_data -> t_ctid ,
5226
+ XLTW_LockUpdated );
5215
5227
goto l4 ;
5216
5228
}
5217
5229
if (res != HeapTupleMayBeUpdated )
@@ -6076,6 +6088,15 @@ HeapTupleGetUpdateXid(HeapTupleHeader tuple)
6076
6088
* Do_MultiXactIdWait
6077
6089
* Actual implementation for the two functions below.
6078
6090
*
6091
+ * 'multi', 'status' and 'infomask' indicate what to sleep on (the status is
6092
+ * needed to ensure we only sleep on conflicting members, and the infomask is
6093
+ * used to optimize multixact access in case it's a lock-only multi); 'nowait'
6094
+ * indicates whether to use conditional lock acquisition, to allow callers to
6095
+ * fail if lock is unavailable. 'rel', 'ctid' and 'oper' are used to set up
6096
+ * context information for error messages. 'remaining', if not NULL, receives
6097
+ * the number of members that are still running, including any (non-aborted)
6098
+ * subtransactions of our own transaction.
6099
+ *
6079
6100
* We do this by sleeping on each member using XactLockTableWait. Any
6080
6101
* members that belong to the current backend are *not* waited for, however;
6081
6102
* this would not merely be useless but would lead to Assert failure inside
@@ -6093,7 +6114,9 @@ HeapTupleGetUpdateXid(HeapTupleHeader tuple)
6093
6114
*/
6094
6115
static bool
6095
6116
Do_MultiXactIdWait (MultiXactId multi , MultiXactStatus status ,
6096
- int * remaining , uint16 infomask , bool nowait )
6117
+ uint16 infomask , bool nowait ,
6118
+ Relation rel , ItemPointer ctid , XLTW_Oper oper ,
6119
+ int * remaining )
6097
6120
{
6098
6121
bool allow_old ;
6099
6122
bool result = true;
@@ -6130,6 +6153,12 @@ Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status,
6130
6153
/*
6131
6154
* This member conflicts with our multi, so we have to sleep (or
6132
6155
* return failure, if asked to avoid waiting.)
6156
+ *
6157
+ * Note that we don't set up an error context callback ourselves,
6158
+ * but instead we pass the info down to XactLockTableWait. This
6159
+ * might seem a bit wasteful because the context is set up and
6160
+ * tore down for each member of the multixact, but in reality it
6161
+ * should be barely noticeable, and it avoids duplicate code.
6133
6162
*/
6134
6163
if (nowait )
6135
6164
{
@@ -6138,7 +6167,7 @@ Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status,
6138
6167
break ;
6139
6168
}
6140
6169
else
6141
- XactLockTableWait (memxid );
6170
+ XactLockTableWait (memxid , rel , ctid , oper );
6142
6171
}
6143
6172
6144
6173
pfree (members );
@@ -6159,13 +6188,14 @@ Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status,
6159
6188
*
6160
6189
* We return (in *remaining, if not NULL) the number of members that are still
6161
6190
* running, including any (non-aborted) subtransactions of our own transaction.
6162
- *
6163
6191
*/
6164
6192
static void
6165
- MultiXactIdWait (MultiXactId multi , MultiXactStatus status ,
6166
- int * remaining , uint16 infomask )
6193
+ MultiXactIdWait (MultiXactId multi , MultiXactStatus status , uint16 infomask ,
6194
+ Relation rel , ItemPointer ctid , XLTW_Oper oper ,
6195
+ int * remaining )
6167
6196
{
6168
- Do_MultiXactIdWait (multi , status , remaining , infomask , false);
6197
+ (void ) Do_MultiXactIdWait (multi , status , infomask , false,
6198
+ rel , ctid , oper , remaining );
6169
6199
}
6170
6200
6171
6201
/*
@@ -6183,9 +6213,11 @@ MultiXactIdWait(MultiXactId multi, MultiXactStatus status,
6183
6213
*/
6184
6214
static bool
6185
6215
ConditionalMultiXactIdWait (MultiXactId multi , MultiXactStatus status ,
6186
- int * remaining , uint16 infomask )
6216
+ uint16 infomask , Relation rel , ItemPointer ctid ,
6217
+ XLTW_Oper oper , int * remaining )
6187
6218
{
6188
- return Do_MultiXactIdWait (multi , status , remaining , infomask , true);
6219
+ return Do_MultiXactIdWait (multi , status , infomask , true,
6220
+ rel , ctid , oper , remaining );
6189
6221
}
6190
6222
6191
6223
/*
0 commit comments