Skip to content

Commit

Permalink
Fix(levels): Avoid a deadlock when acquiring read locks in levels (#1744
Browse files Browse the repository at this point in the history
)
  • Loading branch information
manishrjain committed Sep 14, 2021
1 parent 292a4be commit 560e319
Showing 1 changed file with 16 additions and 2 deletions.
18 changes: 16 additions & 2 deletions levels.go
Expand Up @@ -1120,8 +1120,22 @@ func (s *levelsController) fillTablesL0ToL0(cd *compactDef) bool {
cd.nextRange = keyRange{}
cd.bot = nil

cd.lockLevels()
defer cd.unlockLevels()
// Because this level and next level are both level 0, we should NOT acquire
// the read lock twice, because it can result in a deadlock. So, we don't
// call compactDef.lockLevels, instead locking the level only once and
// directly here.
//
// As per godocs on RWMutex:
// If a goroutine holds a RWMutex for reading and another goroutine might
// call Lock, no goroutine should expect to be able to acquire a read lock
// until the initial read lock is released. In particular, this prohibits
// recursive read locking. This is to ensure that the lock eventually
// becomes available; a blocked Lock call excludes new readers from
// acquiring the lock.
y.AssertTrue(cd.thisLevel.level == 0)
y.AssertTrue(cd.nextLevel.level == 0)
s.levels[0].RLock()
defer s.levels[0].RUnlock()

s.cstatus.Lock()
defer s.cstatus.Unlock()
Expand Down

0 comments on commit 560e319

Please sign in to comment.