fix potential deadlock in View

As pointed out by magik, it is possible to deadlock if the view callback performs
a blockstore operation while a Lock is pending.
This fixes the issue by optimistically tracking the reference before actually calling
the underlying View and limiting the scope of the lock.
This commit is contained in:
vyzo 2021-07-08 21:18:59 +03:00
parent c0537848b3
commit 60dd97c7fc

View File

@ -376,19 +376,19 @@ func (s *SplitStore) HashOnRead(enabled bool) {
} }
func (s *SplitStore) View(cid cid.Cid, cb func([]byte) error) error { func (s *SplitStore) View(cid cid.Cid, cb func([]byte) error) error {
// optimistically protect the reference so that we can call the underlying View
// without holding hte lock.
// This allows the user callback to call into the blockstore without deadlocking.
s.txnLk.RLock() s.txnLk.RLock()
defer s.txnLk.RUnlock() err := s.trackTxnRef(cid)
s.txnLk.RUnlock()
err := s.hot.View(cid, cb)
switch err {
case nil:
err = s.trackTxnRef(cid)
if err != nil { if err != nil {
log.Warnf("error tracking reference to %s: %s", cid, err) log.Warnf("error tracking reference to %s: %s", cid, err)
} }
return nil err = s.hot.View(cid, cb)
switch err {
case bstore.ErrNotFound: case bstore.ErrNotFound:
if s.debug != nil { if s.debug != nil {
s.mx.Lock() s.mx.Lock()