@@ -788,14 +788,16 @@ LockAcquireExtended(const LOCKTAG *locktag,
788788}
789789
790790/*
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.
794793 *
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.
797797 *
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().
799801 */
800802if (lockmode >=AccessExclusiveLock &&
801803locktag -> locktag_type == LOCKTAG_RELATION &&
@@ -816,8 +818,8 @@ LockAcquireExtended(const LOCKTAG *locktag,
816818 * lock type on a relation we have already locked using the fast-path, but
817819 * for now we don't worry about that case either.
818820 */
819- if (EligibleForRelationFastPath (locktag ,lockmode )
820- && FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND )
821+ if (EligibleForRelationFastPath (locktag ,lockmode )&&
822+ FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND )
821823{
822824uint32 fasthashcode = FastPathStrongLockHashPartition (hashcode );
823825bool acquired ;
@@ -837,6 +839,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
837839LWLockRelease (MyProc -> backendLock );
838840if (acquired )
839841{
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 ;
840849GrantLockLocal (locallock ,owner );
841850return LOCKACQUIRE_OK ;
842851}
@@ -877,7 +886,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
877886LWLockAcquire (partitionLock ,LW_EXCLUSIVE );
878887
879888/*
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.
881896 */
882897proclock = SetupLockInTable (lockMethodTable ,MyProc ,locktag ,
883898hashcode ,lockmode );
@@ -1010,7 +1025,7 @@ LockAcquireExtended(const LOCKTAG *locktag,
10101025LWLockRelease (partitionLock );
10111026
10121027/*
1013- * Emit a WAL record if acquisition of this lockneed to be replayed in a
1028+ * Emit a WAL record if acquisition of this lockneeds to be replayed in a
10141029 * standby server.
10151030 */
10161031if (log_lock )
@@ -1049,11 +1064,6 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
10491064
10501065/*
10511066 * 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.
10571067 */
10581068lock = (LOCK * )hash_search_with_hash_value (LockMethodLockHash ,
10591069(const void * )locktag ,
@@ -1821,8 +1831,8 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
18211831return TRUE;
18221832
18231833/* Attempt fast release of any lock eligible for the fast path. */
1824- if (EligibleForRelationFastPath (locktag ,lockmode )
1825- && FastPathLocalUseCount > 0 )
1834+ if (EligibleForRelationFastPath (locktag ,lockmode )&&
1835+ FastPathLocalUseCount > 0 )
18261836{
18271837bool released ;
18281838
@@ -1852,30 +1862,33 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
18521862 * Normally, we don't need to re-find the lock or proclock, since we kept
18531863 * their addresses in the locallock table, and they couldn't have been
18541864 * removed while we were holding a lock on them. But it's possible that
1855- * the locks have been moved to the main hash table by another backend, in
1856- * which case we might need to go look them up after all.
1865+ * the lock was taken fast-path and has since been moved to the main hash
1866+ * table by another backend, in which case we will need to look up the
1867+ * objects here. We assume the lock field is NULL if so.
18571868 */
18581869lock = locallock -> lock ;
18591870if (!lock )
18601871{
18611872PROCLOCKTAG proclocktag ;
1862- bool found ;
18631873
18641874Assert (EligibleForRelationFastPath (locktag ,lockmode ));
18651875lock = (LOCK * )hash_search_with_hash_value (LockMethodLockHash ,
18661876(const void * )locktag ,
18671877locallock -> hashcode ,
18681878HASH_FIND ,
1869- & found );
1870- Assert (found && lock != NULL );
1879+ NULL );
1880+ if (!lock )
1881+ elog (ERROR ,"failed to re-find shared lock object" );
18711882locallock -> lock = lock ;
18721883
18731884proclocktag .myLock = lock ;
18741885proclocktag .myProc = MyProc ;
18751886locallock -> proclock = (PROCLOCK * )hash_search (LockMethodProcLockHash ,
18761887 (void * )& proclocktag ,
1877- HASH_FIND ,& found );
1878- Assert (found );
1888+ HASH_FIND ,
1889+ NULL );
1890+ if (!locallock -> proclock )
1891+ elog (ERROR ,"failed to re-find shared proclock object" );
18791892}
18801893LOCK_PRINT ("LockRelease: found" ,lock ,lockmode );
18811894proclock = locallock -> proclock ;
@@ -1956,7 +1969,8 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
19561969 * entries, then we scan the process's proclocks and get rid of those. We
19571970 * do this separately because we may have multiple locallock entries
19581971 * pointing to the same proclock, and we daren't end up with any dangling
1959- * pointers.
1972+ * pointers. Fast-path locks are cleaned up during the locallock table
1973+ * scan, though.
19601974 */
19611975hash_seq_init (& status ,LockMethodLocalHash );
19621976
@@ -2011,7 +2025,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
20112025
20122026/*
20132027 * If the lock or proclock pointers are NULL, this lock was taken via
2014- * the relation fast-path.
2028+ * the relation fast-path (and is not known to have been transferred) .
20152029 */
20162030if (locallock -> proclock == NULL || locallock -> lock == NULL )
20172031{
@@ -2025,7 +2039,10 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
20252039/*
20262040 * If we don't currently hold the LWLock that protects our
20272041 * fast-path data structures, we must acquire it before attempting
2028- * to release the lock via the fast-path.
2042+ * to release the lock via the fast-path. We will continue to
2043+ * hold the LWLock until we're done scanning the locallock table,
2044+ * unless we hit a transferred fast-path lock.(XXX is this
2045+ * really such a good idea? There could be a lot of entries ...)
20292046 */
20302047if (!have_fast_path_lwlock )
20312048{
@@ -2070,6 +2087,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
20702087RemoveLocalLock (locallock );
20712088}
20722089
2090+ /* Done with the fast-path data structures */
20732091if (have_fast_path_lwlock )
20742092LWLockRelease (MyProc -> backendLock );
20752093
@@ -2421,6 +2439,7 @@ FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode)
24212439Assert (!result );
24222440FAST_PATH_CLEAR_LOCKMODE (MyProc ,f ,lockmode );
24232441result = true;
2442+ /* we continue iterating so as to update FastPathLocalUseCount */
24242443}
24252444if (FAST_PATH_GET_BITS (MyProc ,f )!= 0 )
24262445++ FastPathLocalUseCount ;
@@ -2506,6 +2525,9 @@ FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag
25062525FAST_PATH_CLEAR_LOCKMODE (proc ,f ,lockmode );
25072526}
25082527LWLockRelease (partitionLock );
2528+
2529+ /* No need to examine remaining slots. */
2530+ break ;
25092531}
25102532LWLockRelease (proc -> backendLock );
25112533}
@@ -2516,6 +2538,8 @@ FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag
25162538 * FastPathGetLockEntry
25172539 *Return the PROCLOCK for a lock originally taken via the fast-path,
25182540 *transferring it to the primary lock table if necessary.
2541+ *
2542+ * Note: caller takes care of updating the locallock object.
25192543 */
25202544static PROCLOCK *
25212545FastPathGetRelationLockEntry (LOCALLOCK * locallock )
@@ -2559,6 +2583,9 @@ FastPathGetRelationLockEntry(LOCALLOCK *locallock)
25592583FAST_PATH_CLEAR_LOCKMODE (MyProc ,f ,lockmode );
25602584
25612585LWLockRelease (partitionLock );
2586+
2587+ /* No need to examine remaining slots. */
2588+ break ;
25622589}
25632590
25642591LWLockRelease (MyProc -> backendLock );
@@ -2731,6 +2758,8 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
27312758 */
27322759if (VirtualTransactionIdIsValid (vxid ))
27332760vxids [count ++ ]= vxid ;
2761+
2762+ /* No need to examine remaining slots. */
27342763break ;
27352764}
27362765