@@ -773,14 +773,16 @@ LockAcquireExtended(const LOCKTAG *locktag,
773773}
774774
775775/*
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.
779778 *
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.
782782 *
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().
784786 */
785787if (lockmode >=AccessExclusiveLock &&
786788locktag -> locktag_type == LOCKTAG_RELATION &&
@@ -801,8 +803,8 @@ LockAcquireExtended(const LOCKTAG *locktag,
801803 * lock type on a relation we have already locked using the fast-path, but
802804 * for now we don't worry about that case either.
803805 */
804- if (EligibleForRelationFastPath (locktag ,lockmode )
805- && FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND )
806+ if (EligibleForRelationFastPath (locktag ,lockmode )&&
807+ FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND )
806808{
807809uint32 fasthashcode = FastPathStrongLockHashPartition (hashcode );
808810bool acquired ;
@@ -822,6 +824,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
822824LWLockRelease (MyProc -> backendLock );
823825if (acquired )
824826{
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 ;
825834GrantLockLocal (locallock ,owner );
826835return LOCKACQUIRE_OK ;
827836}
@@ -862,7 +871,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
862871LWLockAcquire (partitionLock ,LW_EXCLUSIVE );
863872
864873/*
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.
866881 */
867882proclock = SetupLockInTable (lockMethodTable ,MyProc ,locktag ,
868883hashcode ,lockmode );
@@ -995,7 +1010,7 @@ LockAcquireExtended(const LOCKTAG *locktag,
9951010LWLockRelease (partitionLock );
9961011
9971012/*
998- * Emit a WAL record if acquisition of this lockneed to be replayed in a
1013+ * Emit a WAL record if acquisition of this lockneeds to be replayed in a
9991014 * standby server.
10001015 */
10011016if (log_lock )
@@ -1034,11 +1049,6 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
10341049
10351050/*
10361051 * 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.
10421052 */
10431053lock = (LOCK * )hash_search_with_hash_value (LockMethodLockHash ,
10441054(const void * )locktag ,
@@ -1794,8 +1804,8 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
17941804return TRUE;
17951805
17961806/* 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 )
17991809{
18001810bool released ;
18011811
@@ -1825,30 +1835,33 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
18251835 * Normally, we don't need to re-find the lock or proclock, since we kept
18261836 * their addresses in the locallock table, and they couldn't have been
18271837 * 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.
18301841 */
18311842lock = locallock -> lock ;
18321843if (!lock )
18331844{
18341845PROCLOCKTAG proclocktag ;
1835- bool found ;
18361846
18371847Assert (EligibleForRelationFastPath (locktag ,lockmode ));
18381848lock = (LOCK * )hash_search_with_hash_value (LockMethodLockHash ,
18391849(const void * )locktag ,
18401850locallock -> hashcode ,
18411851HASH_FIND ,
1842- & found );
1843- Assert (found && lock != NULL );
1852+ NULL );
1853+ if (!lock )
1854+ elog (ERROR ,"failed to re-find shared lock object" );
18441855locallock -> lock = lock ;
18451856
18461857proclocktag .myLock = lock ;
18471858proclocktag .myProc = MyProc ;
18481859locallock -> proclock = (PROCLOCK * )hash_search (LockMethodProcLockHash ,
18491860 (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" );
18521865}
18531866LOCK_PRINT ("LockRelease: found" ,lock ,lockmode );
18541867proclock = locallock -> proclock ;
@@ -1929,7 +1942,8 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
19291942 * entries, then we scan the process's proclocks and get rid of those. We
19301943 * do this separately because we may have multiple locallock entries
19311944 * 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.
19331947 */
19341948hash_seq_init (& status ,LockMethodLocalHash );
19351949
@@ -1983,7 +1997,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
19831997
19841998/*
19851999 * 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) .
19872001 */
19882002if (locallock -> proclock == NULL || locallock -> lock == NULL )
19892003{
@@ -1997,7 +2011,10 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
19972011/*
19982012 * If we don't currently hold the LWLock that protects our
19992013 * 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 ...)
20012018 */
20022019if (!have_fast_path_lwlock )
20032020{
@@ -2042,6 +2059,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
20422059RemoveLocalLock (locallock );
20432060}
20442061
2062+ /* Done with the fast-path data structures */
20452063if (have_fast_path_lwlock )
20462064LWLockRelease (MyProc -> backendLock );
20472065
@@ -2352,6 +2370,7 @@ FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode)
23522370Assert (!result );
23532371FAST_PATH_CLEAR_LOCKMODE (MyProc ,f ,lockmode );
23542372result = true;
2373+ /* we continue iterating so as to update FastPathLocalUseCount */
23552374}
23562375if (FAST_PATH_GET_BITS (MyProc ,f )!= 0 )
23572376++ FastPathLocalUseCount ;
@@ -2437,6 +2456,9 @@ FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag
24372456FAST_PATH_CLEAR_LOCKMODE (proc ,f ,lockmode );
24382457}
24392458LWLockRelease (partitionLock );
2459+
2460+ /* No need to examine remaining slots. */
2461+ break ;
24402462}
24412463LWLockRelease (proc -> backendLock );
24422464}
@@ -2447,6 +2469,8 @@ FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag
24472469 * FastPathGetLockEntry
24482470 *Return the PROCLOCK for a lock originally taken via the fast-path,
24492471 *transferring it to the primary lock table if necessary.
2472+ *
2473+ * Note: caller takes care of updating the locallock object.
24502474 */
24512475static PROCLOCK *
24522476FastPathGetRelationLockEntry (LOCALLOCK * locallock )
@@ -2490,6 +2514,9 @@ FastPathGetRelationLockEntry(LOCALLOCK *locallock)
24902514FAST_PATH_CLEAR_LOCKMODE (MyProc ,f ,lockmode );
24912515
24922516LWLockRelease (partitionLock );
2517+
2518+ /* No need to examine remaining slots. */
2519+ break ;
24932520}
24942521
24952522LWLockRelease (MyProc -> backendLock );
@@ -2662,6 +2689,8 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
26622689 */
26632690if (VirtualTransactionIdIsValid (vxid ))
26642691vxids [count ++ ]= vxid ;
2692+
2693+ /* No need to examine remaining slots. */
26652694break ;
26662695}
26672696