@@ -773,14 +773,16 @@ LockAcquireExtended(const LOCKTAG *locktag,
773
773
}
774
774
775
775
/*
776
- * Emit a WAL record if acquisition of this lock needs to be replayed in a
777
- * standby server. Only AccessExclusiveLocks can conflict with lock types
778
- * that read-only transactions can acquire in a standby server.
776
+ * Prepare to emit a WAL record if acquisition of this lock needs to be
777
+ * replayed in a standby server.
779
778
*
780
- * Make sure this definition matches the one in
781
- * GetRunningTransactionLocks().
779
+ * Here we prepare to log; after lock is acquired we'll issue log record.
780
+ * This arrangement simplifies error recovery in case the preparation step
781
+ * fails.
782
782
*
783
- * First we prepare to log, then after lock acquired we issue log record.
783
+ * Only AccessExclusiveLocks can conflict with lock types that read-only
784
+ * transactions can acquire in a standby server. Make sure this definition
785
+ * matches the one in GetRunningTransactionLocks().
784
786
*/
785
787
if (lockmode >= AccessExclusiveLock &&
786
788
locktag -> locktag_type == LOCKTAG_RELATION &&
@@ -801,8 +803,8 @@ LockAcquireExtended(const LOCKTAG *locktag,
801
803
* lock type on a relation we have already locked using the fast-path, but
802
804
* for now we don't worry about that case either.
803
805
*/
804
- if (EligibleForRelationFastPath (locktag , lockmode )
805
- && FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND )
806
+ if (EligibleForRelationFastPath (locktag , lockmode ) &&
807
+ FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND )
806
808
{
807
809
uint32 fasthashcode = FastPathStrongLockHashPartition (hashcode );
808
810
bool acquired ;
@@ -822,6 +824,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
822
824
LWLockRelease (MyProc -> backendLock );
823
825
if (acquired )
824
826
{
827
+ /*
828
+ * The locallock might contain stale pointers to some old shared
829
+ * objects; we MUST reset these to null before considering the
830
+ * lock to be acquired via fast-path.
831
+ */
832
+ locallock -> lock = NULL ;
833
+ locallock -> proclock = NULL ;
825
834
GrantLockLocal (locallock , owner );
826
835
return LOCKACQUIRE_OK ;
827
836
}
@@ -862,7 +871,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
862
871
LWLockAcquire (partitionLock , LW_EXCLUSIVE );
863
872
864
873
/*
865
- * Find or create a proclock entry with this tag
874
+ * Find or create lock and proclock entries with this tag
875
+ *
876
+ * Note: if the locallock object already existed, it might have a pointer
877
+ * to the lock already ... but we should not assume that that pointer is
878
+ * valid, since a lock object with zero hold and request counts can go
879
+ * away anytime. So we have to use SetupLockInTable() to recompute the
880
+ * lock and proclock pointers, even if they're already set.
866
881
*/
867
882
proclock = SetupLockInTable (lockMethodTable , MyProc , locktag ,
868
883
hashcode , lockmode );
@@ -995,7 +1010,7 @@ LockAcquireExtended(const LOCKTAG *locktag,
995
1010
LWLockRelease (partitionLock );
996
1011
997
1012
/*
998
- * Emit a WAL record if acquisition of this lock need to be replayed in a
1013
+ * Emit a WAL record if acquisition of this lock needs to be replayed in a
999
1014
* standby server.
1000
1015
*/
1001
1016
if (log_lock )
@@ -1034,11 +1049,6 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
1034
1049
1035
1050
/*
1036
1051
* Find or create a lock with this tag.
1037
- *
1038
- * Note: if the locallock object already existed, it might have a pointer
1039
- * to the lock already ... but we probably should not assume that that
1040
- * pointer is valid, since a lock object with no locks can go away
1041
- * anytime.
1042
1052
*/
1043
1053
lock = (LOCK * ) hash_search_with_hash_value (LockMethodLockHash ,
1044
1054
(const void * ) locktag ,
@@ -1794,8 +1804,8 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
1794
1804
return TRUE;
1795
1805
1796
1806
/* Attempt fast release of any lock eligible for the fast path. */
1797
- if (EligibleForRelationFastPath (locktag , lockmode )
1798
- && FastPathLocalUseCount > 0 )
1807
+ if (EligibleForRelationFastPath (locktag , lockmode ) &&
1808
+ FastPathLocalUseCount > 0 )
1799
1809
{
1800
1810
bool released ;
1801
1811
@@ -1825,30 +1835,33 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
1825
1835
* Normally, we don't need to re-find the lock or proclock, since we kept
1826
1836
* their addresses in the locallock table, and they couldn't have been
1827
1837
* removed while we were holding a lock on them. But it's possible that
1828
- * the locks have been moved to the main hash table by another backend, in
1829
- * which case we might need to go look them up after all.
1838
+ * the lock was taken fast-path and has since been moved to the main hash
1839
+ * table by another backend, in which case we will need to look up the
1840
+ * objects here. We assume the lock field is NULL if so.
1830
1841
*/
1831
1842
lock = locallock -> lock ;
1832
1843
if (!lock )
1833
1844
{
1834
1845
PROCLOCKTAG proclocktag ;
1835
- bool found ;
1836
1846
1837
1847
Assert (EligibleForRelationFastPath (locktag , lockmode ));
1838
1848
lock = (LOCK * ) hash_search_with_hash_value (LockMethodLockHash ,
1839
1849
(const void * ) locktag ,
1840
1850
locallock -> hashcode ,
1841
1851
HASH_FIND ,
1842
- & found );
1843
- Assert (found && lock != NULL );
1852
+ NULL );
1853
+ if (!lock )
1854
+ elog (ERROR , "failed to re-find shared lock object" );
1844
1855
locallock -> lock = lock ;
1845
1856
1846
1857
proclocktag .myLock = lock ;
1847
1858
proclocktag .myProc = MyProc ;
1848
1859
locallock -> proclock = (PROCLOCK * ) hash_search (LockMethodProcLockHash ,
1849
1860
(void * ) & proclocktag ,
1850
- HASH_FIND , & found );
1851
- Assert (found );
1861
+ HASH_FIND ,
1862
+ NULL );
1863
+ if (!locallock -> proclock )
1864
+ elog (ERROR , "failed to re-find shared proclock object" );
1852
1865
}
1853
1866
LOCK_PRINT ("LockRelease: found" , lock , lockmode );
1854
1867
proclock = locallock -> proclock ;
@@ -1929,7 +1942,8 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
1929
1942
* entries, then we scan the process's proclocks and get rid of those. We
1930
1943
* do this separately because we may have multiple locallock entries
1931
1944
* pointing to the same proclock, and we daren't end up with any dangling
1932
- * pointers.
1945
+ * pointers. Fast-path locks are cleaned up during the locallock table
1946
+ * scan, though.
1933
1947
*/
1934
1948
hash_seq_init (& status , LockMethodLocalHash );
1935
1949
@@ -1983,7 +1997,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
1983
1997
1984
1998
/*
1985
1999
* If the lock or proclock pointers are NULL, this lock was taken via
1986
- * the relation fast-path.
2000
+ * the relation fast-path (and is not known to have been transferred) .
1987
2001
*/
1988
2002
if (locallock -> proclock == NULL || locallock -> lock == NULL )
1989
2003
{
@@ -1997,7 +2011,10 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
1997
2011
/*
1998
2012
* If we don't currently hold the LWLock that protects our
1999
2013
* fast-path data structures, we must acquire it before attempting
2000
- * to release the lock via the fast-path.
2014
+ * to release the lock via the fast-path. We will continue to
2015
+ * hold the LWLock until we're done scanning the locallock table,
2016
+ * unless we hit a transferred fast-path lock. (XXX is this
2017
+ * really such a good idea? There could be a lot of entries ...)
2001
2018
*/
2002
2019
if (!have_fast_path_lwlock )
2003
2020
{
@@ -2042,6 +2059,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
2042
2059
RemoveLocalLock (locallock );
2043
2060
}
2044
2061
2062
+ /* Done with the fast-path data structures */
2045
2063
if (have_fast_path_lwlock )
2046
2064
LWLockRelease (MyProc -> backendLock );
2047
2065
@@ -2352,6 +2370,7 @@ FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode)
2352
2370
Assert (!result );
2353
2371
FAST_PATH_CLEAR_LOCKMODE (MyProc , f , lockmode );
2354
2372
result = true;
2373
+ /* we continue iterating so as to update FastPathLocalUseCount */
2355
2374
}
2356
2375
if (FAST_PATH_GET_BITS (MyProc , f ) != 0 )
2357
2376
++ FastPathLocalUseCount ;
@@ -2437,6 +2456,9 @@ FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag
2437
2456
FAST_PATH_CLEAR_LOCKMODE (proc , f , lockmode );
2438
2457
}
2439
2458
LWLockRelease (partitionLock );
2459
+
2460
+ /* No need to examine remaining slots. */
2461
+ break ;
2440
2462
}
2441
2463
LWLockRelease (proc -> backendLock );
2442
2464
}
@@ -2447,6 +2469,8 @@ FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag
2447
2469
* FastPathGetLockEntry
2448
2470
* Return the PROCLOCK for a lock originally taken via the fast-path,
2449
2471
* transferring it to the primary lock table if necessary.
2472
+ *
2473
+ * Note: caller takes care of updating the locallock object.
2450
2474
*/
2451
2475
static PROCLOCK *
2452
2476
FastPathGetRelationLockEntry (LOCALLOCK * locallock )
@@ -2490,6 +2514,9 @@ FastPathGetRelationLockEntry(LOCALLOCK *locallock)
2490
2514
FAST_PATH_CLEAR_LOCKMODE (MyProc , f , lockmode );
2491
2515
2492
2516
LWLockRelease (partitionLock );
2517
+
2518
+ /* No need to examine remaining slots. */
2519
+ break ;
2493
2520
}
2494
2521
2495
2522
LWLockRelease (MyProc -> backendLock );
@@ -2662,6 +2689,8 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
2662
2689
*/
2663
2690
if (VirtualTransactionIdIsValid (vxid ))
2664
2691
vxids [count ++ ] = vxid ;
2692
+
2693
+ /* No need to examine remaining slots. */
2665
2694
break ;
2666
2695
}
2667
2696
0 commit comments