From 1d674905e0c1f6bd712362da941664c3063cfe5f Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 20 Mar 2014 00:10:44 -0500 Subject: [PATCH] Introduce a chain state to block manager. This commit introduces a chain state that is updated as blocks are processed into the block chain instance associated with the block manager. This has been done because btcchain is currently not safe for concurrent access and the block manager is typically quite busy processing block and inventory. This approach allows fast access to most chain information in a concurrent safe fashion. --- blockmanager.go | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/blockmanager.go b/blockmanager.go index 740c65bd..57cae6cd 100644 --- a/blockmanager.go +++ b/blockmanager.go @@ -83,6 +83,20 @@ type headerNode struct { sha *btcwire.ShaHash } +// chainState tracks the state of the best chain as blocks are inserted. This +// is done because btcchain is currently not safe for concurrent access and the +// block manager is typically quite busy processing block and inventory. +// Therefore, requesting this information from chain through the block manager +// would not be anywhere near as efficient as simply updating it as each block +// is inserted and protecting it with a mutex. +type chainState struct { + sync.Mutex + newestHash *btcwire.ShaHash + newestHeight int64 + pastMedianTime time.Time + pastMedianTimeErr error +} + // blockManager provides a concurrency safe block manager for handling all // incoming blocks. type blockManager struct { @@ -99,6 +113,7 @@ type blockManager struct { processingReqs bool syncPeer *peer msgChan chan interface{} + chainState chainState wg sync.WaitGroup quit chan bool @@ -125,6 +140,24 @@ func (b *blockManager) resetHeaderState(newestHash *btcwire.ShaHash, newestHeigh } } +// updateChainState updates the chain state associated with the block manager. +// This allows fast access to chain information since btcchain is currently not +// safe for concurrent access and the block manager is typically quite busy +// processing block and inventory. +func (b *blockManager) updateChainState(newestHash *btcwire.ShaHash, newestHeight int64) { + b.chainState.Lock() + defer b.chainState.Unlock() + + b.chainState.newestHash = newestHash + b.chainState.newestHeight = newestHeight + medianTime, err := b.blockChain.CalcPastMedianTime() + if err != nil { + b.chainState.pastMedianTimeErr = err + } else { + b.chainState.pastMedianTime = medianTime + } +} + // findNextHeaderCheckpoint returns the next checkpoint after the passed height. // It returns nil when there is not one either because the height is already // later than the final checkpoint or some other reason such as disabled @@ -510,10 +543,12 @@ func (b *blockManager) handleBlockMsg(bmsg *blockMsg) { } // When the block is not an orphan, don't keep track of the peer that - // sent it any longer and log information about it. + // sent it any longer, log information about it, and update the chain + // state. if !b.blockChain.IsKnownOrphan(blockSha) { delete(b.blockPeer, *blockSha) b.logBlockHeight(bmsg.block) + b.updateChainState(blockSha, bmsg.block.Height()) } // Sync the db to disk. @@ -1158,6 +1193,10 @@ func newBlockManager(s *server) (*blockManager, error) { } bmgrLog.Infof("Block index generation complete") + // Initialize the chain state now that the intial block node index has + // been generated. + bm.updateChainState(newestHash, height) + return &bm, nil }