-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(concurrency): applying blocks concurrently can lead to unexpected errors #700
Changes from 13 commits
a66eb8c
663ae77
d388822
c276b07
dd0a575
45cecf0
69521b3
6433abc
481c705
d343dca
3fd1aa5
8ad28b5
e234d07
0a43157
8c9a1ac
a329116
086e320
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -118,9 +118,10 @@ func (m *Manager) applyBlock(block *types.Block, commit *types.Commit, blockMeta | |
return nil | ||
} | ||
|
||
// TODO: move to gossip.go | ||
func (m *Manager) attemptApplyCachedBlocks() error { | ||
m.applyCachedBlockMutex.Lock() | ||
defer m.applyCachedBlockMutex.Unlock() | ||
m.executeBlockMutex.Lock() | ||
defer m.executeBlockMutex.Unlock() | ||
|
||
for { | ||
expectedHeight := m.store.NextHeight() | ||
|
@@ -140,13 +141,17 @@ func (m *Manager) attemptApplyCachedBlocks() error { | |
m.logger.Debug("applied cached block", "height", expectedHeight) | ||
} | ||
|
||
return nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed the pruning from each gossiped block, as it's not efficient, it goes over all the cached blocks. |
||
} | ||
|
||
// pruneCache prunes the cache of gossiped blocks. | ||
func (m *Manager) pruneCache() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure why we need this pruneCache vs just deleting each cached block after we apply it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it was to handle the cases blocks didn't applied from cache, but from syncTarge |
||
for k := range m.prevBlock { | ||
if k <= m.store.Height() { | ||
delete(m.prevBlock, k) | ||
delete(m.prevCommit, k) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// isHeightAlreadyApplied checks if the block height is already applied to the app. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as mentioned before, I think it's best to have this lock on the ApplyBlock function (and change it's name accordingly) as even if you get the race condition on NextHeight as current block with this height is currently being applied, the
ApplyBlock
have a sanity check on correct height and the block won't be applied.I think it makes the code much more elegant and simplifies reading and the needs of dealing with future
applyBlock
callers.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this mutex is not only for applyBlock
it mutex between
retriever
thread andgossip
threadthere are multiple params that can be accessed concurrently and needs protection (e.g blockCache, store height, "state" (apply block))
I can change it if u prefer, but IMO it's not hermetic enough