Remove races on chain.
Chain is not concurrency safe, so we move the chainNotifySink handling into the main blockmanager goroutine. Due to a possible deadlock if the buffer is filled this still has to be a single channel that isn't linked to the other ones. There is a possible starvation issue where the main msgChan gets selected more often than the notification sink, but until chain is concurrency safe this is rather unavoidable.
This commit is contained in:
parent
8974e789f7
commit
eb667fdf83
1 changed files with 7 additions and 23 deletions
|
@ -406,6 +406,10 @@ out:
|
||||||
default:
|
default:
|
||||||
// bitch and whine.
|
// bitch and whine.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case not := <- b.chainNotifySink:
|
||||||
|
b.handleNotifyMsg(not)
|
||||||
|
|
||||||
case <-b.quit:
|
case <-b.quit:
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
|
@ -459,25 +463,6 @@ func (b *blockManager) handleNotifyMsg(notification *btcchain.Notification) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// chainNotificationSinkHandler is the sink for the chain notification handler.
|
|
||||||
// It actually responds to the notifications so the main chain notification
|
|
||||||
// handler does not block chain while processing notifications. It must be run
|
|
||||||
// as a goroutine.
|
|
||||||
func (b *blockManager) chainNotificationSinkHandler() {
|
|
||||||
out:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case notification := <-b.chainNotifySink:
|
|
||||||
b.handleNotifyMsg(notification)
|
|
||||||
|
|
||||||
case <-b.quit:
|
|
||||||
break out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.wg.Done()
|
|
||||||
log.Trace("[BMGR] Chain notification sink done")
|
|
||||||
}
|
|
||||||
|
|
||||||
// chainNotificationHandler is the handler for asynchronous notifications from
|
// chainNotificationHandler is the handler for asynchronous notifications from
|
||||||
// btcchain. It must be run as a goroutine.
|
// btcchain. It must be run as a goroutine.
|
||||||
func (b *blockManager) chainNotificationHandler() {
|
func (b *blockManager) chainNotificationHandler() {
|
||||||
|
@ -491,10 +476,10 @@ out:
|
||||||
// Sending on a nil channel always blocks and hence is ignored
|
// Sending on a nil channel always blocks and hence is ignored
|
||||||
// by select. Thus enable send only when the list is non-empty.
|
// by select. Thus enable send only when the list is non-empty.
|
||||||
var firstItem *btcchain.Notification
|
var firstItem *btcchain.Notification
|
||||||
var chainNotifySink chan *btcchain.Notification
|
var chainNotifySink chan interface{}
|
||||||
if pending.Len() > 0 {
|
if pending.Len() > 0 {
|
||||||
firstItem = pending.Front().Value.(*btcchain.Notification)
|
firstItem = pending.Front().Value.(*btcchain.Notification)
|
||||||
chainNotifySink = b.chainNotifySink
|
chainNotifySink = b.msgChan
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
@ -562,9 +547,8 @@ func (b *blockManager) Start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace("[BMGR] Starting block manager")
|
log.Trace("[BMGR] Starting block manager")
|
||||||
b.wg.Add(3)
|
b.wg.Add(2)
|
||||||
go b.blockHandler()
|
go b.blockHandler()
|
||||||
go b.chainNotificationSinkHandler()
|
|
||||||
go b.chainNotificationHandler()
|
go b.chainNotificationHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue