@@ -409,8 +409,7 @@ static PROCLOCK *SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
409
409
static void GrantLockLocal (LOCALLOCK * locallock , ResourceOwner owner );
410
410
static void BeginStrongLockAcquire (LOCALLOCK * locallock , uint32 fasthashcode );
411
411
static void FinishStrongLockAcquire (void );
412
- static void WaitOnLock (LOCALLOCK * locallock , ResourceOwner owner ,
413
- bool dontWait );
412
+ static ProcWaitStatus WaitOnLock (LOCALLOCK * locallock , ResourceOwner owner );
414
413
static void ReleaseLockIfHeld (LOCALLOCK * locallock , bool sessionLock );
415
414
static void LockReassignOwner (LOCALLOCK * locallock , ResourceOwner parent );
416
415
static bool UnGrantLock (LOCK * lock , LOCKMODE lockmode ,
@@ -843,6 +842,7 @@ LockAcquireExtended(const LOCKTAG *locktag,
843
842
uint32 hashcode ;
844
843
LWLock * partitionLock ;
845
844
bool found_conflict ;
845
+ ProcWaitStatus waitResult ;
846
846
bool log_lock = false;
847
847
848
848
if (lockmethodid <= 0 || lockmethodid >= lengthof (LockMethods ))
@@ -1091,94 +1091,115 @@ LockAcquireExtended(const LOCKTAG *locktag,
1091
1091
{
1092
1092
/* No conflict with held or previously requested locks */
1093
1093
GrantLock (lock , proclock , lockmode );
1094
- GrantLockLocal ( locallock , owner ) ;
1094
+ waitResult = PROC_WAIT_STATUS_OK ;
1095
1095
}
1096
1096
else
1097
1097
{
1098
1098
/*
1099
- * Sleep till someone wakes me up. We do this even in the dontWait
1100
- * case, because while trying to go to sleep, we may discover that we
1101
- * can acquire the lock immediately after all.
1099
+ * Join the lock's wait queue. We call this even in the dontWait
1100
+ * case, because JoinWaitQueue() may discover that we can acquire the
1101
+ * lock immediately after all.
1102
+ */
1103
+ waitResult = JoinWaitQueue (locallock , lockMethodTable , dontWait );
1104
+ }
1105
+
1106
+ if (waitResult == PROC_WAIT_STATUS_ERROR )
1107
+ {
1108
+ /*
1109
+ * We're not getting the lock because a deadlock was detected already
1110
+ * while trying to join the wait queue, or because we would have to
1111
+ * wait but the caller requested no blocking.
1112
+ *
1113
+ * Undo the changes to shared entries before releasing the partition
1114
+ * lock.
1102
1115
*/
1103
- WaitOnLock (locallock , owner , dontWait );
1116
+ AbortStrongLockAcquire ();
1117
+
1118
+ if (proclock -> holdMask == 0 )
1119
+ {
1120
+ uint32 proclock_hashcode ;
1121
+
1122
+ proclock_hashcode = ProcLockHashCode (& proclock -> tag ,
1123
+ hashcode );
1124
+ dlist_delete (& proclock -> lockLink );
1125
+ dlist_delete (& proclock -> procLink );
1126
+ if (!hash_search_with_hash_value (LockMethodProcLockHash ,
1127
+ & (proclock -> tag ),
1128
+ proclock_hashcode ,
1129
+ HASH_REMOVE ,
1130
+ NULL ))
1131
+ elog (PANIC , "proclock table corrupted" );
1132
+ }
1133
+ else
1134
+ PROCLOCK_PRINT ("LockAcquire: did not join wait queue" , proclock );
1135
+ lock -> nRequested -- ;
1136
+ lock -> requested [lockmode ]-- ;
1137
+ LOCK_PRINT ("LockAcquire: did not join wait queue" ,
1138
+ lock , lockmode );
1139
+ Assert ((lock -> nRequested > 0 ) &&
1140
+ (lock -> requested [lockmode ] >= 0 ));
1141
+ Assert (lock -> nGranted <= lock -> nRequested );
1142
+ LWLockRelease (partitionLock );
1143
+ if (locallock -> nLocks == 0 )
1144
+ RemoveLocalLock (locallock );
1145
+
1146
+ if (dontWait )
1147
+ {
1148
+ if (locallockp )
1149
+ * locallockp = NULL ;
1150
+ return LOCKACQUIRE_NOT_AVAIL ;
1151
+ }
1152
+ else
1153
+ {
1154
+ DeadLockReport ();
1155
+ /* DeadLockReport() will not return */
1156
+ }
1157
+ }
1158
+
1159
+ /*
1160
+ * We are now in the lock queue, or the lock was already granted. If
1161
+ * queued, go to sleep.
1162
+ */
1163
+ if (waitResult == PROC_WAIT_STATUS_WAITING )
1164
+ {
1165
+ Assert (!dontWait );
1166
+ PROCLOCK_PRINT ("LockAcquire: sleeping on lock" , proclock );
1167
+ LOCK_PRINT ("LockAcquire: sleeping on lock" , lock , lockmode );
1168
+ LWLockRelease (partitionLock );
1169
+
1170
+ waitResult = WaitOnLock (locallock , owner );
1104
1171
1105
1172
/*
1106
1173
* NOTE: do not do any material change of state between here and
1107
1174
* return. All required changes in locktable state must have been
1108
1175
* done when the lock was granted to us --- see notes in WaitOnLock.
1109
1176
*/
1110
1177
1111
- /*
1112
- * Check the proclock entry status. If dontWait = true, this is an
1113
- * expected case; otherwise, it will only happen if something in the
1114
- * ipc communication doesn't work correctly.
1115
- */
1116
- if (!(proclock -> holdMask & LOCKBIT_ON (lockmode )))
1178
+ if (waitResult == PROC_WAIT_STATUS_ERROR )
1117
1179
{
1118
- AbortStrongLockAcquire ();
1119
-
1120
- if (dontWait )
1121
- {
1122
- /*
1123
- * We can't acquire the lock immediately. If caller specified
1124
- * no blocking, remove useless table entries and return
1125
- * LOCKACQUIRE_NOT_AVAIL without waiting.
1126
- */
1127
- if (proclock -> holdMask == 0 )
1128
- {
1129
- uint32 proclock_hashcode ;
1130
-
1131
- proclock_hashcode = ProcLockHashCode (& proclock -> tag ,
1132
- hashcode );
1133
- dlist_delete (& proclock -> lockLink );
1134
- dlist_delete (& proclock -> procLink );
1135
- if (!hash_search_with_hash_value (LockMethodProcLockHash ,
1136
- & (proclock -> tag ),
1137
- proclock_hashcode ,
1138
- HASH_REMOVE ,
1139
- NULL ))
1140
- elog (PANIC , "proclock table corrupted" );
1141
- }
1142
- else
1143
- PROCLOCK_PRINT ("LockAcquire: NOWAIT" , proclock );
1144
- lock -> nRequested -- ;
1145
- lock -> requested [lockmode ]-- ;
1146
- LOCK_PRINT ("LockAcquire: conditional lock failed" ,
1147
- lock , lockmode );
1148
- Assert ((lock -> nRequested > 0 ) &&
1149
- (lock -> requested [lockmode ] >= 0 ));
1150
- Assert (lock -> nGranted <= lock -> nRequested );
1151
- LWLockRelease (partitionLock );
1152
- if (locallock -> nLocks == 0 )
1153
- RemoveLocalLock (locallock );
1154
- if (locallockp )
1155
- * locallockp = NULL ;
1156
- return LOCKACQUIRE_NOT_AVAIL ;
1157
- }
1158
- else
1159
- {
1160
- /*
1161
- * We should have gotten the lock, but somehow that didn't
1162
- * happen. If we get here, it's a bug.
1163
- */
1164
- PROCLOCK_PRINT ("LockAcquire: INCONSISTENT" , proclock );
1165
- LOCK_PRINT ("LockAcquire: INCONSISTENT" , lock , lockmode );
1166
- LWLockRelease (partitionLock );
1167
- elog (ERROR , "LockAcquire failed" );
1168
- }
1180
+ /*
1181
+ * We failed as a result of a deadlock, see CheckDeadLock(). Quit
1182
+ * now.
1183
+ */
1184
+ Assert (!dontWait );
1185
+ DeadLockReport ();
1186
+ /* DeadLockReport() will not return */
1169
1187
}
1170
- PROCLOCK_PRINT ("LockAcquire: granted" , proclock );
1171
- LOCK_PRINT ("LockAcquire: granted" , lock , lockmode );
1172
1188
}
1189
+ else
1190
+ LWLockRelease (partitionLock );
1191
+ Assert (waitResult == PROC_WAIT_STATUS_OK );
1192
+
1193
+ /* The lock was granted to us. Update the local lock entry accordingly */
1194
+ Assert ((proclock -> holdMask & LOCKBIT_ON (lockmode )) != 0 );
1195
+ GrantLockLocal (locallock , owner );
1173
1196
1174
1197
/*
1175
1198
* Lock state is fully up-to-date now; if we error out after this, no
1176
1199
* special error cleanup is required.
1177
1200
*/
1178
1201
FinishStrongLockAcquire ();
1179
1202
1180
- LWLockRelease (partitionLock );
1181
-
1182
1203
/*
1183
1204
* Emit a WAL record if acquisition of this lock needs to be replayed in a
1184
1205
* standby server.
@@ -1819,6 +1840,15 @@ GrantAwaitedLock(void)
1819
1840
GrantLockLocal (awaitedLock , awaitedOwner );
1820
1841
}
1821
1842
1843
+ /*
1844
+ * GetAwaitedLock -- Return the lock we're currently doing WaitOnLock on.
1845
+ */
1846
+ LOCALLOCK *
1847
+ GetAwaitedLock (void )
1848
+ {
1849
+ return awaitedLock ;
1850
+ }
1851
+
1822
1852
/*
1823
1853
* MarkLockClear -- mark an acquired lock as "clear"
1824
1854
*
@@ -1836,14 +1866,12 @@ MarkLockClear(LOCALLOCK *locallock)
1836
1866
/*
1837
1867
* WaitOnLock -- wait to acquire a lock
1838
1868
*
1839
- * The appropriate partition lock must be held at entry, and will still be
1840
- * held at exit.
1869
+ * This is a wrapper around ProcSleep, with extra tracing and bookkeeping.
1841
1870
*/
1842
- static void
1843
- WaitOnLock (LOCALLOCK * locallock , ResourceOwner owner , bool dontWait )
1871
+ static ProcWaitStatus
1872
+ WaitOnLock (LOCALLOCK * locallock , ResourceOwner owner )
1844
1873
{
1845
- LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD (* locallock );
1846
- LockMethod lockMethodTable = LockMethods [lockmethodid ];
1874
+ ProcWaitStatus result ;
1847
1875
1848
1876
TRACE_POSTGRESQL_LOCK_WAIT_START (locallock -> tag .lock .locktag_field1 ,
1849
1877
locallock -> tag .lock .locktag_field2 ,
@@ -1852,12 +1880,13 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner, bool dontWait)
1852
1880
locallock -> tag .lock .locktag_type ,
1853
1881
locallock -> tag .mode );
1854
1882
1855
- LOCK_PRINT ("WaitOnLock: sleeping on lock" ,
1856
- locallock -> lock , locallock -> tag .mode );
1857
-
1858
1883
/* adjust the process title to indicate that it's waiting */
1859
1884
set_ps_display_suffix ("waiting" );
1860
1885
1886
+ /*
1887
+ * Record the fact that we are waiting for a lock, so that
1888
+ * LockErrorCleanup will clean up if cancel/die happens.
1889
+ */
1861
1890
awaitedLock = locallock ;
1862
1891
awaitedOwner = owner ;
1863
1892
@@ -1880,30 +1909,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner, bool dontWait)
1880
1909
*/
1881
1910
PG_TRY ();
1882
1911
{
1883
- /*
1884
- * If dontWait = true, we handle success and failure in the same way
1885
- * here. The caller will be able to sort out what has happened.
1886
- */
1887
- if (ProcSleep (locallock , lockMethodTable , dontWait ) != PROC_WAIT_STATUS_OK
1888
- && !dontWait )
1889
- {
1890
-
1891
- /*
1892
- * We failed as a result of a deadlock, see CheckDeadLock(). Quit
1893
- * now.
1894
- */
1895
- awaitedLock = NULL ;
1896
- LOCK_PRINT ("WaitOnLock: aborting on lock" ,
1897
- locallock -> lock , locallock -> tag .mode );
1898
- LWLockRelease (LockHashPartitionLock (locallock -> hashcode ));
1899
-
1900
- /*
1901
- * Now that we aren't holding the partition lock, we can give an
1902
- * error report including details about the detected deadlock.
1903
- */
1904
- DeadLockReport ();
1905
- /* not reached */
1906
- }
1912
+ result = ProcSleep (locallock );
1907
1913
}
1908
1914
PG_CATCH ();
1909
1915
{
@@ -1917,20 +1923,22 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner, bool dontWait)
1917
1923
}
1918
1924
PG_END_TRY ();
1919
1925
1926
+ /*
1927
+ * We no longer want LockErrorCleanup to do anything.
1928
+ */
1920
1929
awaitedLock = NULL ;
1921
1930
1922
1931
/* reset ps display to remove the suffix */
1923
1932
set_ps_display_remove_suffix ();
1924
1933
1925
- LOCK_PRINT ("WaitOnLock: wakeup on lock" ,
1926
- locallock -> lock , locallock -> tag .mode );
1927
-
1928
1934
TRACE_POSTGRESQL_LOCK_WAIT_DONE (locallock -> tag .lock .locktag_field1 ,
1929
1935
locallock -> tag .lock .locktag_field2 ,
1930
1936
locallock -> tag .lock .locktag_field3 ,
1931
1937
locallock -> tag .lock .locktag_field4 ,
1932
1938
locallock -> tag .lock .locktag_type ,
1933
1939
locallock -> tag .mode );
1940
+
1941
+ return result ;
1934
1942
}
1935
1943
1936
1944
/*
0 commit comments