Pre-allocate space for high use slices.

This commit modifies the code to choose sane defaults for the backing
arrays for slices that involve a lot of appends such block locators, hash
processing, and needed transactions.  This is an optimization to avoid
the overhead of growing the backing arrays and copying the data multiple
times in the most common case.  This also prevents a leak in Go GC which
will likely ultimatley be fixed, but the efficiecy gains alone are worth
the change.
This commit is contained in:
Dave Collins 2013-09-25 20:20:53 -05:00
parent d1f1fe0752
commit 2f743b4821
3 changed files with 19 additions and 3 deletions

View file

@ -29,7 +29,8 @@ type BlockLocator []*btcwire.ShaHash
// consist of the passed hash
func (b *BlockChain) BlockLocatorFromHash(hash *btcwire.ShaHash) BlockLocator {
// The locator contains the requested hash at the very least.
locator := BlockLocator([]*btcwire.ShaHash{hash})
locator := make(BlockLocator, 0, btcwire.MaxBlockLocatorsPerMsg)
locator = append(locator, hash)
// Nothing more to do if a locator for the genesis hash was requested.
if hash.IsEqual(b.chainParams().GenesisHash) {

View file

@ -38,10 +38,15 @@ func (b *BlockChain) blockExists(hash *btcwire.ShaHash) bool {
// It repeats the process for the newly accepted blocks (to detect further
// orphans which may no longer be orphans) until there are no more.
func (b *BlockChain) processOrphans(hash *btcwire.ShaHash) error {
processHashes := []*btcwire.ShaHash{hash}
// Start with processing at least the passed hash. Leave a little room
// for additional orphan blocks that need to be processed without
// needing to grow the array in the common case.
processHashes := make([]*btcwire.ShaHash, 0, 10)
processHashes = append(processHashes, hash)
for len(processHashes) > 0 {
// Pop the first hash to process from the slice.
processHash := processHashes[0]
processHashes[0] = nil // Prevent GC leak.
processHashes = processHashes[1:]
// Look up all orphans that are parented by the block we just

View file

@ -215,10 +215,20 @@ func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Bloc
txInFlight[*txHash] = i
}
// Make a reasonable guess for the maximum number of needed input
// transactions to use as the starting point for the needed transactions
// array. The array will dynamically grow as needed, but it's much less
// overhead to avoid growing and copying the array multiple times in the
// common case. Each block usually has no more than ten inputs per
// transaction, so use that as a reasonable starting point. A block
// with 2,000 transactions would only result in around 156KB on a 64-bit
// system using this approach.
maxNeededHint := (len(transactions) - 1) * 10
txNeededList := make([]*btcwire.ShaHash, 0, maxNeededHint)
// Loop through all of the transaction inputs (except for the coinbase
// which has no inputs) collecting them into lists of what is needed and
// what is already known (in-flight).
var txNeededList []*btcwire.ShaHash
txStore := make(map[btcwire.ShaHash]*txData)
for i, tx := range transactions[1:] {
for _, txIn := range tx.TxIn {