@@ -788,14 +788,16 @@ LockAcquireExtended(const LOCKTAG *locktag,
788
788
}
789
789
790
790
/*
791
- * Emit a WAL record if acquisition of this lock needs to be replayed in a
792
- * standby server. Only AccessExclusiveLocks can conflict with lock types
793
- * that read-only transactions can acquire in a standby server.
791
+ * Prepare to emit a WAL record if acquisition of this lock needs to be
792
+ * replayed in a standby server.
794
793
*
795
- * Make sure this definition matches the one in
796
- * GetRunningTransactionLocks().
794
+ * Here we prepare to log; after lock is acquired we'll issue log record.
795
+ * This arrangement simplifies error recovery in case the preparation step
796
+ * fails.
797
797
*
798
- * First we prepare to log, then after lock acquired we issue log record.
798
+ * Only AccessExclusiveLocks can conflict with lock types that read-only
799
+ * transactions can acquire in a standby server. Make sure this definition
800
+ * matches the one in GetRunningTransactionLocks().
799
801
*/
800
802
if (lockmode >= AccessExclusiveLock &&
801
803
locktag -> locktag_type == LOCKTAG_RELATION &&
@@ -816,8 +818,8 @@ LockAcquireExtended(const LOCKTAG *locktag,
816
818
* lock type on a relation we have already locked using the fast-path, but
817
819
* for now we don't worry about that case either.
818
820
*/
819
- if (EligibleForRelationFastPath (locktag , lockmode )
820
- && FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND )
821
+ if (EligibleForRelationFastPath (locktag , lockmode ) &&
822
+ FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND )
821
823
{
822
824
uint32 fasthashcode = FastPathStrongLockHashPartition (hashcode );
823
825
bool acquired ;
@@ -837,6 +839,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
837
839
LWLockRelease (MyProc -> backendLock );
838
840
if (acquired )
839
841
{
842
+ /*
843
+ * The locallock might contain stale pointers to some old shared
844
+ * objects; we MUST reset these to null before considering the
845
+ * lock to be acquired via fast-path.
846
+ */
847
+ locallock -> lock = NULL ;
848
+ locallock -> proclock = NULL ;
840
849
GrantLockLocal (locallock , owner );
841
850
return LOCKACQUIRE_OK ;
842
851
}
@@ -877,7 +886,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
877
886
LWLockAcquire (partitionLock , LW_EXCLUSIVE );
878
887
879
888
/*
880
- * Find or create a proclock entry with this tag
889
+ * Find or create lock and proclock entries with this tag
890
+ *
891
+ * Note: if the locallock object already existed, it might have a pointer
892
+ * to the lock already ... but we should not assume that that pointer is
893
+ * valid, since a lock object with zero hold and request counts can go
894
+ * away anytime. So we have to use SetupLockInTable() to recompute the
895
+ * lock and proclock pointers, even if they're already set.
881
896
*/
882
897
proclock = SetupLockInTable (lockMethodTable , MyProc , locktag ,
883
898
hashcode , lockmode );
@@ -1010,7 +1025,7 @@ LockAcquireExtended(const LOCKTAG *locktag,
1010
1025
LWLockRelease (partitionLock );
1011
1026
1012
1027
/*
1013
- * Emit a WAL record if acquisition of this lock need to be replayed in a
1028
+ * Emit a WAL record if acquisition of this lock needs to be replayed in a
1014
1029
* standby server.
1015
1030
*/
1016
1031
if (log_lock )
@@ -1049,11 +1064,6 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
1049
1064
1050
1065
/*
1051
1066
* Find or create a lock with this tag.
1052
- *
1053
- * Note: if the locallock object already existed, it might have a pointer
1054
- * to the lock already ... but we probably should not assume that that
1055
- * pointer is valid, since a lock object with no locks can go away
1056
- * anytime.
1057
1067
*/
1058
1068
lock = (LOCK * ) hash_search_with_hash_value (LockMethodLockHash ,
1059
1069
(const void * ) locktag ,
@@ -1822,8 +1832,8 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
1822
1832
return TRUE;
1823
1833
1824
1834
/* Attempt fast release of any lock eligible for the fast path. */
1825
- if (EligibleForRelationFastPath (locktag , lockmode )
1826
- && FastPathLocalUseCount > 0 )
1835
+ if (EligibleForRelationFastPath (locktag , lockmode ) &&
1836
+ FastPathLocalUseCount > 0 )
1827
1837
{
1828
1838
bool released ;
1829
1839
@@ -1853,30 +1863,33 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
1853
1863
* Normally, we don't need to re-find the lock or proclock, since we kept
1854
1864
* their addresses in the locallock table, and they couldn't have been
1855
1865
* removed while we were holding a lock on them. But it's possible that
1856
- * the locks have been moved to the main hash table by another backend, in
1857
- * which case we might need to go look them up after all.
1866
+ * the lock was taken fast-path and has since been moved to the main hash
1867
+ * table by another backend, in which case we will need to look up the
1868
+ * objects here. We assume the lock field is NULL if so.
1858
1869
*/
1859
1870
lock = locallock -> lock ;
1860
1871
if (!lock )
1861
1872
{
1862
1873
PROCLOCKTAG proclocktag ;
1863
- bool found ;
1864
1874
1865
1875
Assert (EligibleForRelationFastPath (locktag , lockmode ));
1866
1876
lock = (LOCK * ) hash_search_with_hash_value (LockMethodLockHash ,
1867
1877
(const void * ) locktag ,
1868
1878
locallock -> hashcode ,
1869
1879
HASH_FIND ,
1870
- & found );
1871
- Assert (found && lock != NULL );
1880
+ NULL );
1881
+ if (!lock )
1882
+ elog (ERROR , "failed to re-find shared lock object" );
1872
1883
locallock -> lock = lock ;
1873
1884
1874
1885
proclocktag .myLock = lock ;
1875
1886
proclocktag .myProc = MyProc ;
1876
1887
locallock -> proclock = (PROCLOCK * ) hash_search (LockMethodProcLockHash ,
1877
1888
(void * ) & proclocktag ,
1878
- HASH_FIND , & found );
1879
- Assert (found );
1889
+ HASH_FIND ,
1890
+ NULL );
1891
+ if (!locallock -> proclock )
1892
+ elog (ERROR , "failed to re-find shared proclock object" );
1880
1893
}
1881
1894
LOCK_PRINT ("LockRelease: found" , lock , lockmode );
1882
1895
proclock = locallock -> proclock ;
@@ -1957,7 +1970,8 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
1957
1970
* entries, then we scan the process's proclocks and get rid of those. We
1958
1971
* do this separately because we may have multiple locallock entries
1959
1972
* pointing to the same proclock, and we daren't end up with any dangling
1960
- * pointers.
1973
+ * pointers. Fast-path locks are cleaned up during the locallock table
1974
+ * scan, though.
1961
1975
*/
1962
1976
hash_seq_init (& status , LockMethodLocalHash );
1963
1977
@@ -2012,7 +2026,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
2012
2026
2013
2027
/*
2014
2028
* If the lock or proclock pointers are NULL, this lock was taken via
2015
- * the relation fast-path.
2029
+ * the relation fast-path (and is not known to have been transferred) .
2016
2030
*/
2017
2031
if (locallock -> proclock == NULL || locallock -> lock == NULL )
2018
2032
{
@@ -2026,7 +2040,10 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
2026
2040
/*
2027
2041
* If we don't currently hold the LWLock that protects our
2028
2042
* fast-path data structures, we must acquire it before attempting
2029
- * to release the lock via the fast-path.
2043
+ * to release the lock via the fast-path. We will continue to
2044
+ * hold the LWLock until we're done scanning the locallock table,
2045
+ * unless we hit a transferred fast-path lock. (XXX is this
2046
+ * really such a good idea? There could be a lot of entries ...)
2030
2047
*/
2031
2048
if (!have_fast_path_lwlock )
2032
2049
{
@@ -2071,6 +2088,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
2071
2088
RemoveLocalLock (locallock );
2072
2089
}
2073
2090
2091
+ /* Done with the fast-path data structures */
2074
2092
if (have_fast_path_lwlock )
2075
2093
LWLockRelease (MyProc -> backendLock );
2076
2094
@@ -2422,6 +2440,7 @@ FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode)
2422
2440
Assert (!result );
2423
2441
FAST_PATH_CLEAR_LOCKMODE (MyProc , f , lockmode );
2424
2442
result = true;
2443
+ /* we continue iterating so as to update FastPathLocalUseCount */
2425
2444
}
2426
2445
if (FAST_PATH_GET_BITS (MyProc , f ) != 0 )
2427
2446
++ FastPathLocalUseCount ;
@@ -2507,6 +2526,9 @@ FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag
2507
2526
FAST_PATH_CLEAR_LOCKMODE (proc , f , lockmode );
2508
2527
}
2509
2528
LWLockRelease (partitionLock );
2529
+
2530
+ /* No need to examine remaining slots. */
2531
+ break ;
2510
2532
}
2511
2533
LWLockRelease (proc -> backendLock );
2512
2534
}
@@ -2517,6 +2539,8 @@ FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag
2517
2539
* FastPathGetLockEntry
2518
2540
* Return the PROCLOCK for a lock originally taken via the fast-path,
2519
2541
* transferring it to the primary lock table if necessary.
2542
+ *
2543
+ * Note: caller takes care of updating the locallock object.
2520
2544
*/
2521
2545
static PROCLOCK *
2522
2546
FastPathGetRelationLockEntry (LOCALLOCK * locallock )
@@ -2560,6 +2584,9 @@ FastPathGetRelationLockEntry(LOCALLOCK *locallock)
2560
2584
FAST_PATH_CLEAR_LOCKMODE (MyProc , f , lockmode );
2561
2585
2562
2586
LWLockRelease (partitionLock );
2587
+
2588
+ /* No need to examine remaining slots. */
2589
+ break ;
2563
2590
}
2564
2591
2565
2592
LWLockRelease (MyProc -> backendLock );
@@ -2732,6 +2759,8 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
2732
2759
*/
2733
2760
if (VirtualTransactionIdIsValid (vxid ))
2734
2761
vxids [count ++ ] = vxid ;
2762
+
2763
+ /* No need to examine remaining slots. */
2735
2764
break ;
2736
2765
}
2737
2766
0 commit comments