Browse Source

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
pull/7932/merge
Chris Lu 2 days ago
committed by GitHub
parent
commit
08b79a30f6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 16
      weed/util/lock_table.go
  2. 44
      weed/util/lock_table_test.go

16
weed/util/lock_table.go

@ -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()
} }
} }

44
weed/util/lock_table_test.go

@ -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")
}
}
Loading…
Cancel
Save