Fix lock table shared wait condition (#8707)
* Fix lock table shared wait condition (#8696) * Refactor lock table waiter check * Add exclusive lock wait helper test
This commit is contained in:
@@ -52,6 +52,18 @@ func (lt *LockTable[T]) NewActiveLock(intention string, lockType LockType) *Acti
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isNotFirstWaiter(lock *ActiveLock, entry *LockEntry) bool {
|
||||||
|
return len(entry.waiters) > 0 && lock.ID != entry.waiters[0].ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldWaitForExclusiveLock(lock *ActiveLock, entry *LockEntry) bool {
|
||||||
|
return !lock.isDeleted && (isNotFirstWaiter(lock, entry) || entry.activeExclusiveLockOwnerCount > 0 || entry.activeSharedLockOwnerCount > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldWaitForSharedLock(lock *ActiveLock, entry *LockEntry) bool {
|
||||||
|
return !lock.isDeleted && (isNotFirstWaiter(lock, entry) || entry.activeExclusiveLockOwnerCount > 0)
|
||||||
|
}
|
||||||
|
|
||||||
func (lt *LockTable[T]) AcquireLock(intention string, key T, lockType LockType) (lock *ActiveLock) {
|
func (lt *LockTable[T]) AcquireLock(intention string, key T, lockType LockType) (lock *ActiveLock) {
|
||||||
lt.mu.Lock()
|
lt.mu.Lock()
|
||||||
// Get or create the lock entry for the key
|
// Get or create the lock entry for the key
|
||||||
@@ -81,11 +93,11 @@ func (lt *LockTable[T]) AcquireLock(intention string, key T, lockType LockType)
|
|||||||
}
|
}
|
||||||
entry.waiters = append(entry.waiters, lock)
|
entry.waiters = append(entry.waiters, lock)
|
||||||
if lockType == ExclusiveLock {
|
if lockType == ExclusiveLock {
|
||||||
for !lock.isDeleted && ((len(entry.waiters) > 0 && lock.ID != entry.waiters[0].ID) || entry.activeExclusiveLockOwnerCount > 0 || entry.activeSharedLockOwnerCount > 0) {
|
for shouldWaitForExclusiveLock(lock, entry) {
|
||||||
entry.cond.Wait()
|
entry.cond.Wait()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for !lock.isDeleted && (len(entry.waiters) > 0 && lock.ID != entry.waiters[0].ID) || entry.activeExclusiveLockOwnerCount > 0 {
|
for shouldWaitForSharedLock(lock, entry) {
|
||||||
entry.cond.Wait()
|
entry.cond.Wait()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,3 +40,47 @@ func TestOrderedLock(t *testing.T) {
|
|||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShouldWaitForSharedLock(t *testing.T) {
|
||||||
|
lock := &ActiveLock{ID: 2, lockType: SharedLock}
|
||||||
|
entry := &LockEntry{
|
||||||
|
waiters: []*ActiveLock{{ID: 1}, lock},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !shouldWaitForSharedLock(lock, entry) {
|
||||||
|
t.Fatal("shared lock should wait behind earlier waiters")
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.waiters = []*ActiveLock{lock}
|
||||||
|
entry.activeExclusiveLockOwnerCount = 1
|
||||||
|
if !shouldWaitForSharedLock(lock, entry) {
|
||||||
|
t.Fatal("shared lock should wait while an exclusive owner is active")
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.isDeleted = true
|
||||||
|
if shouldWaitForSharedLock(lock, entry) {
|
||||||
|
t.Fatal("deleted shared lock should stop waiting even if an exclusive owner is active")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldWaitForExclusiveLock(t *testing.T) {
|
||||||
|
lock := &ActiveLock{ID: 2, lockType: ExclusiveLock}
|
||||||
|
entry := &LockEntry{
|
||||||
|
waiters: []*ActiveLock{{ID: 1}, lock},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !shouldWaitForExclusiveLock(lock, entry) {
|
||||||
|
t.Fatal("exclusive lock should wait behind earlier waiters")
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.waiters = []*ActiveLock{lock}
|
||||||
|
entry.activeSharedLockOwnerCount = 1
|
||||||
|
if !shouldWaitForExclusiveLock(lock, entry) {
|
||||||
|
t.Fatal("exclusive lock should wait while shared owners are active")
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.isDeleted = true
|
||||||
|
if shouldWaitForExclusiveLock(lock, entry) {
|
||||||
|
t.Fatal("deleted exclusive lock should stop waiting even if shared owners are active")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user