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:
Owain G. Ainsworth 2013-10-03 00:50:36 +01:00
parent 8974e789f7
commit eb667fdf83

View file

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