mirror of
https://github.com/LBRYFoundation/lbcwallet.git
synced 2025-09-05 05:15:12 +00:00
chain: use ConcurrentQueue within BitcoindClient to handle event notifications
This commit is contained in:
parent
fc73cc9678
commit
2091ac0936
1 changed files with 22 additions and 109 deletions
|
@ -32,8 +32,7 @@ type BitcoindClient struct {
|
||||||
zmqConnect string
|
zmqConnect string
|
||||||
zmqPollInterval time.Duration
|
zmqPollInterval time.Duration
|
||||||
|
|
||||||
enqueueNotification chan interface{}
|
notificationQueue *ConcurrentQueue
|
||||||
dequeueNotification chan interface{}
|
|
||||||
currentBlock chan *waddrmgr.BlockStamp
|
currentBlock chan *waddrmgr.BlockStamp
|
||||||
|
|
||||||
clientMtx sync.RWMutex
|
clientMtx sync.RWMutex
|
||||||
|
@ -76,8 +75,6 @@ func NewBitcoindClient(chainParams *chaincfg.Params, connect, user, pass,
|
||||||
chainParams: chainParams,
|
chainParams: chainParams,
|
||||||
zmqConnect: zmqConnect,
|
zmqConnect: zmqConnect,
|
||||||
zmqPollInterval: zmqPollInterval,
|
zmqPollInterval: zmqPollInterval,
|
||||||
enqueueNotification: make(chan interface{}),
|
|
||||||
dequeueNotification: make(chan interface{}),
|
|
||||||
currentBlock: make(chan *waddrmgr.BlockStamp),
|
currentBlock: make(chan *waddrmgr.BlockStamp),
|
||||||
rescanUpdate: make(chan interface{}),
|
rescanUpdate: make(chan interface{}),
|
||||||
watchOutPoints: make(map[wire.OutPoint]struct{}),
|
watchOutPoints: make(map[wire.OutPoint]struct{}),
|
||||||
|
@ -389,7 +386,6 @@ func (c *BitcoindClient) Start() error {
|
||||||
c.quitMtx.Unlock()
|
c.quitMtx.Unlock()
|
||||||
|
|
||||||
c.wg.Add(2)
|
c.wg.Add(2)
|
||||||
go c.handler()
|
|
||||||
go c.socketHandler(zmqClient)
|
go c.socketHandler(zmqClient)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -403,10 +399,7 @@ func (c *BitcoindClient) Stop() {
|
||||||
default:
|
default:
|
||||||
close(c.quit)
|
close(c.quit)
|
||||||
c.client.Shutdown()
|
c.client.Shutdown()
|
||||||
|
c.notificationQueue.Stop()
|
||||||
if !c.started {
|
|
||||||
close(c.dequeueNotification)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
c.quitMtx.Unlock()
|
c.quitMtx.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -423,7 +416,7 @@ func (c *BitcoindClient) WaitForShutdown() {
|
||||||
// may abort for running out memory, as unread notifications are queued for
|
// may abort for running out memory, as unread notifications are queued for
|
||||||
// later reads.
|
// later reads.
|
||||||
func (c *BitcoindClient) Notifications() <-chan interface{} {
|
func (c *BitcoindClient) Notifications() <-chan interface{} {
|
||||||
return c.dequeueNotification
|
return c.notificationQueue.ChanOut()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetStartTime is a non-interface method to set the birthday of the wallet
|
// SetStartTime is a non-interface method to set the birthday of the wallet
|
||||||
|
@ -452,7 +445,7 @@ func (c *BitcoindClient) BlockStamp() (*waddrmgr.BlockStamp, error) {
|
||||||
|
|
||||||
func (c *BitcoindClient) onClientConnect() {
|
func (c *BitcoindClient) onClientConnect() {
|
||||||
select {
|
select {
|
||||||
case c.enqueueNotification <- ClientConnected{}:
|
case c.notificationQueue.ChanIn() <- ClientConnected{}:
|
||||||
case <-c.quit:
|
case <-c.quit:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -460,7 +453,7 @@ func (c *BitcoindClient) onClientConnect() {
|
||||||
func (c *BitcoindClient) onBlockConnected(hash *chainhash.Hash, height int32, time time.Time) {
|
func (c *BitcoindClient) onBlockConnected(hash *chainhash.Hash, height int32, time time.Time) {
|
||||||
if c.notifying() {
|
if c.notifying() {
|
||||||
select {
|
select {
|
||||||
case c.enqueueNotification <- BlockConnected{
|
case c.notificationQueue.ChanIn() <- BlockConnected{
|
||||||
Block: wtxmgr.Block{
|
Block: wtxmgr.Block{
|
||||||
Hash: *hash,
|
Hash: *hash,
|
||||||
Height: height,
|
Height: height,
|
||||||
|
@ -476,7 +469,7 @@ func (c *BitcoindClient) onFilteredBlockConnected(height int32,
|
||||||
header *wire.BlockHeader, relevantTxs []*wtxmgr.TxRecord) {
|
header *wire.BlockHeader, relevantTxs []*wtxmgr.TxRecord) {
|
||||||
if c.notifying() {
|
if c.notifying() {
|
||||||
select {
|
select {
|
||||||
case c.enqueueNotification <- FilteredBlockConnected{
|
case c.notificationQueue.ChanIn() <- FilteredBlockConnected{
|
||||||
Block: &wtxmgr.BlockMeta{
|
Block: &wtxmgr.BlockMeta{
|
||||||
Block: wtxmgr.Block{
|
Block: wtxmgr.Block{
|
||||||
Hash: header.BlockHash(),
|
Hash: header.BlockHash(),
|
||||||
|
@ -494,7 +487,7 @@ func (c *BitcoindClient) onFilteredBlockConnected(height int32,
|
||||||
func (c *BitcoindClient) onBlockDisconnected(hash *chainhash.Hash, height int32, time time.Time) {
|
func (c *BitcoindClient) onBlockDisconnected(hash *chainhash.Hash, height int32, time time.Time) {
|
||||||
if c.notifying() {
|
if c.notifying() {
|
||||||
select {
|
select {
|
||||||
case c.enqueueNotification <- BlockDisconnected{
|
case c.notificationQueue.ChanIn() <- BlockDisconnected{
|
||||||
Block: wtxmgr.Block{
|
Block: wtxmgr.Block{
|
||||||
Hash: *hash,
|
Hash: *hash,
|
||||||
Height: height,
|
Height: height,
|
||||||
|
@ -516,14 +509,14 @@ func (c *BitcoindClient) onRelevantTx(rec *wtxmgr.TxRecord,
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case c.enqueueNotification <- RelevantTx{rec, blk}:
|
case c.notificationQueue.ChanIn() <- RelevantTx{rec, blk}:
|
||||||
case <-c.quit:
|
case <-c.quit:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *BitcoindClient) onRescanProgress(hash *chainhash.Hash, height int32, blkTime time.Time) {
|
func (c *BitcoindClient) onRescanProgress(hash *chainhash.Hash, height int32, blkTime time.Time) {
|
||||||
select {
|
select {
|
||||||
case c.enqueueNotification <- &RescanProgress{hash, height, blkTime}:
|
case c.notificationQueue.ChanIn() <- &RescanProgress{hash, height, blkTime}:
|
||||||
case <-c.quit:
|
case <-c.quit:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -531,7 +524,7 @@ func (c *BitcoindClient) onRescanProgress(hash *chainhash.Hash, height int32, bl
|
||||||
func (c *BitcoindClient) onRescanFinished(hash *chainhash.Hash, height int32, blkTime time.Time) {
|
func (c *BitcoindClient) onRescanFinished(hash *chainhash.Hash, height int32, blkTime time.Time) {
|
||||||
log.Infof("Rescan finished at %d (%s)", height, hash)
|
log.Infof("Rescan finished at %d (%s)", height, hash)
|
||||||
select {
|
select {
|
||||||
case c.enqueueNotification <- &RescanFinished{hash, height, blkTime}:
|
case c.notificationQueue.ChanIn() <- &RescanFinished{hash, height, blkTime}:
|
||||||
case <-c.quit:
|
case <-c.quit:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1177,83 +1170,3 @@ func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
|
||||||
|
|
||||||
return notifyTx, rec, nil
|
return notifyTx, rec, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// handler maintains a queue of notifications and the current state (best
|
|
||||||
// block) of the chain.
|
|
||||||
func (c *BitcoindClient) handler() {
|
|
||||||
hash, height, err := c.GetBestBlock()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to receive best block from chain server: %v", err)
|
|
||||||
c.Stop()
|
|
||||||
c.wg.Done()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bs := &waddrmgr.BlockStamp{Hash: *hash, Height: height}
|
|
||||||
|
|
||||||
// TODO: Rather than leaving this as an unbounded queue for all types of
|
|
||||||
// notifications, try dropping ones where a later enqueued notification
|
|
||||||
// can fully invalidate one waiting to be processed. For example,
|
|
||||||
// blockconnected notifications for greater block heights can remove the
|
|
||||||
// need to process earlier blockconnected notifications still waiting
|
|
||||||
// here.
|
|
||||||
|
|
||||||
// TODO(aakselrod): Factor this logic out so it can be reused for each
|
|
||||||
// chain back end, rather than copying it.
|
|
||||||
|
|
||||||
var notifications []interface{}
|
|
||||||
enqueue := c.enqueueNotification
|
|
||||||
var dequeue chan interface{}
|
|
||||||
var next interface{}
|
|
||||||
out:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case n, ok := <-enqueue:
|
|
||||||
if !ok {
|
|
||||||
// If no notifications are queued for handling,
|
|
||||||
// the queue is finished.
|
|
||||||
if len(notifications) == 0 {
|
|
||||||
break out
|
|
||||||
}
|
|
||||||
// nil channel so no more reads can occur.
|
|
||||||
enqueue = nil
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(notifications) == 0 {
|
|
||||||
next = n
|
|
||||||
dequeue = c.dequeueNotification
|
|
||||||
}
|
|
||||||
notifications = append(notifications, n)
|
|
||||||
|
|
||||||
case dequeue <- next:
|
|
||||||
if n, ok := next.(BlockConnected); ok {
|
|
||||||
bs = &waddrmgr.BlockStamp{
|
|
||||||
Height: n.Height,
|
|
||||||
Hash: n.Hash,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
notifications[0] = nil
|
|
||||||
notifications = notifications[1:]
|
|
||||||
if len(notifications) != 0 {
|
|
||||||
next = notifications[0]
|
|
||||||
} else {
|
|
||||||
// If no more notifications can be enqueued, the
|
|
||||||
// queue is finished.
|
|
||||||
if enqueue == nil {
|
|
||||||
break out
|
|
||||||
}
|
|
||||||
dequeue = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
case c.currentBlock <- bs:
|
|
||||||
|
|
||||||
case <-c.quit:
|
|
||||||
break out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Stop()
|
|
||||||
close(c.dequeueNotification)
|
|
||||||
c.wg.Done()
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue