@@ -2784,8 +2784,12 @@ FastPathGetRelationLockEntry(LOCALLOCK *locallock)
2784
2784
*
2785
2785
* The result array is palloc'd and is terminated with an invalid VXID.
2786
2786
*
2787
- * Of course, the result could be out of date by the time it's returned,
2788
- * so use of this function has to be thought about carefully.
2787
+ * Of course, the result could be out of date by the time it's returned, so
2788
+ * use of this function has to be thought about carefully. Similarly, a
2789
+ * PGPROC with no "lxid" will be considered non-conflicting regardless of any
2790
+ * lock it holds. Existing callers don't care about a locker after that
2791
+ * locker's pg_xact updates complete. CommitTransaction() clears "lxid" after
2792
+ * pg_xact updates and before releasing locks.
2789
2793
*
2790
2794
* Note we never include the current xact's vxid in the result array,
2791
2795
* since an xact never blocks itself.
@@ -4402,37 +4406,80 @@ VirtualXactLockTableCleanup(void)
4402
4406
}
4403
4407
}
4404
4408
4409
+ /*
4410
+ * XactLockForVirtualXact
4411
+ *
4412
+ * If TransactionIdIsValid(xid), this is essentially XactLockTableWait(xid,
4413
+ * NULL, NULL, XLTW_None) or ConditionalXactLockTableWait(xid). Unlike those
4414
+ * functions, it assumes "xid" is never a subtransaction and that "xid" is
4415
+ * prepared, committed, or aborted.
4416
+ *
4417
+ * If !TransactionIdIsValid(xid), this locks every prepared XID having been
4418
+ * known as "vxid" before its PREPARE TRANSACTION.
4419
+ */
4420
+ static bool
4421
+ XactLockForVirtualXact (VirtualTransactionId vxid ,
4422
+ TransactionId xid , bool wait )
4423
+ {
4424
+ bool more = false;
4425
+
4426
+ /* There is no point to wait for 2PCs if you have no 2PCs. */
4427
+ if (max_prepared_xacts == 0 )
4428
+ return true;
4429
+
4430
+ do
4431
+ {
4432
+ LockAcquireResult lar ;
4433
+ LOCKTAG tag ;
4434
+
4435
+ /* Clear state from previous iterations. */
4436
+ if (more )
4437
+ {
4438
+ xid = InvalidTransactionId ;
4439
+ more = false;
4440
+ }
4441
+
4442
+ /* If we have no xid, try to find one. */
4443
+ if (!TransactionIdIsValid (xid ))
4444
+ xid = TwoPhaseGetXidByVirtualXID (vxid , & more );
4445
+ if (!TransactionIdIsValid (xid ))
4446
+ {
4447
+ Assert (!more );
4448
+ return true;
4449
+ }
4450
+
4451
+ /* Check or wait for XID completion. */
4452
+ SET_LOCKTAG_TRANSACTION (tag , xid );
4453
+ lar = LockAcquire (& tag , ShareLock , false, !wait );
4454
+ if (lar == LOCKACQUIRE_NOT_AVAIL )
4455
+ return false;
4456
+ LockRelease (& tag , ShareLock , false);
4457
+ } while (more );
4458
+
4459
+ return true;
4460
+ }
4461
+
4405
4462
/*
4406
4463
* VirtualXactLock
4407
4464
*
4408
- * If wait = true, wait until the given VXID has been released, and then
4409
- * return true.
4465
+ * If wait = true, wait as long as the given VXID or any XID acquired by the
4466
+ * same transaction is still running. Then, return true.
4410
4467
*
4411
- * If wait = false, just check whether the VXID is still running, and return
4412
- * true or false.
4468
+ * If wait = false, just check whether that VXID or one of those XIDs is still
4469
+ * running, and return true or false.
4413
4470
*/
4414
4471
bool
4415
4472
VirtualXactLock (VirtualTransactionId vxid , bool wait )
4416
4473
{
4417
4474
LOCKTAG tag ;
4418
4475
PGPROC * proc ;
4476
+ TransactionId xid = InvalidTransactionId ;
4419
4477
4420
4478
Assert (VirtualTransactionIdIsValid (vxid ));
4421
4479
4422
- if (VirtualTransactionIdIsPreparedXact (vxid ))
4423
- {
4424
- LockAcquireResult lar ;
4425
-
4426
- /*
4427
- * Prepared transactions don't hold vxid locks. The
4428
- * LocalTransactionId is always a normal, locked XID.
4429
- */
4430
- SET_LOCKTAG_TRANSACTION (tag , vxid .localTransactionId );
4431
- lar = LockAcquire (& tag , ShareLock , false, !wait );
4432
- if (lar != LOCKACQUIRE_NOT_AVAIL )
4433
- LockRelease (& tag , ShareLock , false);
4434
- return lar != LOCKACQUIRE_NOT_AVAIL ;
4435
- }
4480
+ if (VirtualTransactionIdIsRecoveredPreparedXact (vxid ))
4481
+ /* no vxid lock; localTransactionId is a normal, locked XID */
4482
+ return XactLockForVirtualXact (vxid , vxid .localTransactionId , wait );
4436
4483
4437
4484
SET_LOCKTAG_VIRTUALTRANSACTION (tag , vxid );
4438
4485
@@ -4446,7 +4493,7 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait)
4446
4493
*/
4447
4494
proc = BackendIdGetProc (vxid .backendId );
4448
4495
if (proc == NULL )
4449
- return true ;
4496
+ return XactLockForVirtualXact ( vxid , InvalidTransactionId , wait ) ;
4450
4497
4451
4498
/*
4452
4499
* We must acquire this lock before checking the backendId and lxid
@@ -4455,12 +4502,12 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait)
4455
4502
*/
4456
4503
LWLockAcquire (& proc -> backendLock , LW_EXCLUSIVE );
4457
4504
4458
- /* If the transaction has ended, our work here is done. */
4459
4505
if (proc -> backendId != vxid .backendId
4460
4506
|| proc -> fpLocalTransactionId != vxid .localTransactionId )
4461
4507
{
4508
+ /* VXID ended */
4462
4509
LWLockRelease (& proc -> backendLock );
4463
- return true ;
4510
+ return XactLockForVirtualXact ( vxid , InvalidTransactionId , wait ) ;
4464
4511
}
4465
4512
4466
4513
/*
@@ -4507,14 +4554,24 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait)
4507
4554
proc -> fpVXIDLock = false;
4508
4555
}
4509
4556
4557
+ /*
4558
+ * If the proc has an XID now, we'll avoid a TwoPhaseGetXidByVirtualXID()
4559
+ * search. The proc might have assigned this XID but not yet locked it,
4560
+ * in which case the proc will lock this XID before releasing the VXID.
4561
+ * The backendLock critical section excludes VirtualXactLockTableCleanup(),
4562
+ * so we won't save an XID of a different VXID. It doesn't matter whether
4563
+ * we save this before or after setting up the primary lock table entry.
4564
+ */
4565
+ xid = ProcGlobal -> allPgXact [proc -> pgprocno ].xid ;
4566
+
4510
4567
/* Done with proc->fpLockBits */
4511
4568
LWLockRelease (& proc -> backendLock );
4512
4569
4513
4570
/* Time to wait. */
4514
4571
(void ) LockAcquire (& tag , ShareLock , false, false);
4515
4572
4516
4573
LockRelease (& tag , ShareLock , false);
4517
- return true ;
4574
+ return XactLockForVirtualXact ( vxid , xid , wait ) ;
4518
4575
}
4519
4576
4520
4577
/*
0 commit comments