Pre-allocate space for slices.
Several of the messages store the parts that have a variable number of elements as slices. This commit modifies the code to choose sane defaults for the backing arrays for the slices so when the entries are actually appended, a lot of the overhead of growing the backing arrays and copying the data multiple times is avoided. Along the same lines, when decoding messages, the actual size is known and now is pre-allocated instead of dynamically growing the backing array thereby avoiding some overhead.
This commit is contained in:
parent
e7f808378e
commit
5f971e10e6
10 changed files with 83 additions and 28 deletions
|
@ -70,6 +70,7 @@ func (msg *MsgAddr) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return messageError("MsgAddr.BtcDecode", str)
|
||||
}
|
||||
|
||||
msg.AddrList = make([]*NetAddress, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
na := NetAddress{}
|
||||
err := readNetAddress(r, pver, &na, true)
|
||||
|
@ -135,5 +136,7 @@ func (msg *MsgAddr) MaxPayloadLength(pver uint32) uint32 {
|
|||
// NewMsgAddr returns a new bitcoin addr message that conforms to the
|
||||
// Message interface. See MsgAddr for details.
|
||||
func NewMsgAddr() *MsgAddr {
|
||||
return &MsgAddr{}
|
||||
return &MsgAddr{
|
||||
AddrList: make([]*NetAddress, 0, MaxAddrPerMsg),
|
||||
}
|
||||
}
|
||||
|
|
14
msgblock.go
14
msgblock.go
|
@ -9,6 +9,13 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
// defaultTransactionAlloc is the default size used for the backing array
|
||||
// for transactions. The transaction array will dynamically grow as needed, but
|
||||
// this figure is intended to provide enough space for the number of
|
||||
// transactions in the vast majority of blocks without needing to grow the
|
||||
// backing array multiple times.
|
||||
const defaultTransactionAlloc = 2048
|
||||
|
||||
// MaxBlocksPerMsg is the maximum number of blocks allowed per message.
|
||||
const MaxBlocksPerMsg = 500
|
||||
|
||||
|
@ -51,7 +58,7 @@ func (msg *MsgBlock) AddTransaction(tx *MsgTx) error {
|
|||
// ClearTransactions removes all transactions from the message and updates
|
||||
// Header.TxnCount accordingly.
|
||||
func (msg *MsgBlock) ClearTransactions() {
|
||||
msg.Transactions = []*MsgTx{}
|
||||
msg.Transactions = make([]*MsgTx, 0, defaultTransactionAlloc)
|
||||
msg.Header.TxnCount = 0
|
||||
}
|
||||
|
||||
|
@ -65,6 +72,7 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return err
|
||||
}
|
||||
|
||||
msg.Transactions = make([]*MsgTx, 0, msg.Header.TxnCount)
|
||||
for i := uint64(0); i < msg.Header.TxnCount; i++ {
|
||||
tx := MsgTx{}
|
||||
err := tx.BtcDecode(r, pver)
|
||||
|
@ -110,6 +118,7 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
|||
// Deserialize each transaction while keeping track of its location
|
||||
// within the byte stream.
|
||||
txCount := msg.Header.TxnCount
|
||||
msg.Transactions = make([]*MsgTx, 0, txCount)
|
||||
txLocs := make([]TxLoc, txCount)
|
||||
for i := uint64(0); i < txCount; i++ {
|
||||
txLocs[i].TxStart = fullLen - r.Len()
|
||||
|
@ -184,7 +193,7 @@ func (msg *MsgBlock) BlockSha() (ShaHash, error) {
|
|||
|
||||
// TxShas returns a slice of hashes of all of transactions in this block.
|
||||
func (msg *MsgBlock) TxShas() ([]ShaHash, error) {
|
||||
var shaList []ShaHash
|
||||
shaList := make([]ShaHash, 0, len(msg.Transactions))
|
||||
for _, tx := range msg.Transactions {
|
||||
// Ignore error here since TxSha can't fail in the current
|
||||
// implementation except due to run-time panics.
|
||||
|
@ -199,5 +208,6 @@ func (msg *MsgBlock) TxShas() ([]ShaHash, error) {
|
|||
func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock {
|
||||
return &MsgBlock{
|
||||
Header: *blockHeader,
|
||||
Transactions: make([]*MsgTx, 0, defaultTransactionAlloc),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return messageError("MsgGetBlocks.BtcDecode", str)
|
||||
}
|
||||
|
||||
msg.BlockLocatorHashes = make([]*ShaHash, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
sha := ShaHash{}
|
||||
err := readElement(r, &sha)
|
||||
|
@ -137,6 +138,7 @@ func (msg *MsgGetBlocks) MaxPayloadLength(pver uint32) uint32 {
|
|||
func NewMsgGetBlocks(hashStop *ShaHash) *MsgGetBlocks {
|
||||
return &MsgGetBlocks{
|
||||
ProtocolVersion: ProtocolVersion,
|
||||
BlockLocatorHashes: make([]*ShaHash, 0, MaxBlockLocatorsPerMsg),
|
||||
HashStop: *hashStop,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return messageError("MsgGetData.BtcDecode", str)
|
||||
}
|
||||
|
||||
msg.InvList = make([]*InvVect, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
iv := InvVect{}
|
||||
err := readInvVect(r, pver, &iv)
|
||||
|
@ -102,5 +103,7 @@ func (msg *MsgGetData) MaxPayloadLength(pver uint32) uint32 {
|
|||
// NewMsgGetData returns a new bitcoin getdata message that conforms to the
|
||||
// Message interface. See MsgGetData for details.
|
||||
func NewMsgGetData() *MsgGetData {
|
||||
return &MsgGetData{}
|
||||
return &MsgGetData{
|
||||
InvList: make([]*InvVect, 0, defaultInvListAlloc),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ func (msg *MsgGetHeaders) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return messageError("MsgGetHeaders.BtcDecode", str)
|
||||
}
|
||||
|
||||
msg.BlockLocatorHashes = make([]*ShaHash, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
sha := ShaHash{}
|
||||
err := readElement(r, &sha)
|
||||
|
@ -132,5 +133,7 @@ func (msg *MsgGetHeaders) MaxPayloadLength(pver uint32) uint32 {
|
|||
// NewMsgGetHeaders returns a new bitcoin getheaders message that conforms to
|
||||
// the Message interface. See MsgGetHeaders for details.
|
||||
func NewMsgGetHeaders() *MsgGetHeaders {
|
||||
return &MsgGetHeaders{}
|
||||
return &MsgGetHeaders{
|
||||
BlockLocatorHashes: make([]*ShaHash, 0, MaxBlockLocatorsPerMsg),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return messageError("MsgHeaders.BtcDecode", str)
|
||||
}
|
||||
|
||||
msg.Headers = make([]*BlockHeader, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
bh := BlockHeader{}
|
||||
err := readBlockHeader(r, pver, &bh)
|
||||
|
@ -117,5 +118,7 @@ func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 {
|
|||
// NewMsgHeaders returns a new bitcoin headers message that conforms to the
|
||||
// Message interface. See MsgHeaders for details.
|
||||
func NewMsgHeaders() *MsgHeaders {
|
||||
return &MsgHeaders{}
|
||||
return &MsgHeaders{
|
||||
Headers: make([]*BlockHeader, 0, MaxBlockHeadersPerMsg),
|
||||
}
|
||||
}
|
||||
|
|
14
msginv.go
14
msginv.go
|
@ -9,6 +9,15 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
// defaultInvListAlloc is the default size used for the backing array for an
|
||||
// inventory list. The array will dynamically grow as needed, but this
|
||||
// figure is intended to provide enough space for the max number of inventory
|
||||
// vectors in a *typical* inventory message without needing to grow the backing
|
||||
// array multiple times. Technically, the list can grow to MaxInvPerMsg, but
|
||||
// rather than using that large figure, this figure more accurately reflects the
|
||||
// typical case.
|
||||
const defaultInvListAlloc = 1000
|
||||
|
||||
// MsgInv implements the Message interface and represents a bitcoin inv message.
|
||||
// It is used to advertise a peer's known data such as blocks and transactions
|
||||
// through inventory vectors. It may be sent unsolicited to inform other peers
|
||||
|
@ -48,6 +57,7 @@ func (msg *MsgInv) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return messageError("MsgInv.BtcDecode", str)
|
||||
}
|
||||
|
||||
msg.InvList = make([]*InvVect, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
iv := InvVect{}
|
||||
err := readInvVect(r, pver, &iv)
|
||||
|
@ -101,5 +111,7 @@ func (msg *MsgInv) MaxPayloadLength(pver uint32) uint32 {
|
|||
// NewMsgInv returns a new bitcoin inv message that conforms to the Message
|
||||
// interface. See MsgInv for details.
|
||||
func NewMsgInv() *MsgInv {
|
||||
return &MsgInv{}
|
||||
return &MsgInv{
|
||||
InvList: make([]*InvVect, 0, defaultInvListAlloc),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ func (msg *MsgNotFound) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return messageError("MsgNotFound.BtcDecode", str)
|
||||
}
|
||||
|
||||
msg.InvList = make([]*InvVect, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
iv := InvVect{}
|
||||
err := readInvVect(r, pver, &iv)
|
||||
|
@ -100,5 +101,7 @@ func (msg *MsgNotFound) MaxPayloadLength(pver uint32) uint32 {
|
|||
// NewMsgNotFound returns a new bitcoin notfound message that conforms to the
|
||||
// Message interface. See MsgNotFound for details.
|
||||
func NewMsgNotFound() *MsgNotFound {
|
||||
return &MsgNotFound{}
|
||||
return &MsgNotFound{
|
||||
InvList: make([]*InvVect, 0, defaultInvListAlloc),
|
||||
}
|
||||
}
|
||||
|
|
20
msgtx.go
20
msgtx.go
|
@ -9,6 +9,13 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
// defaultTxInOutAlloc is the default size used for the backing array for
|
||||
// transaction inputs and outputs. The array will dynamically grow as needed,
|
||||
// but this figure is intended to provide enough space for the number of
|
||||
// inputs and outputs in a typical transaction without needing to grow the
|
||||
// backing array multiple times.
|
||||
const defaultTxInOutAlloc = 15
|
||||
|
||||
// TxVersion is the current latest supported transaction version.
|
||||
const TxVersion = 1
|
||||
|
||||
|
@ -110,9 +117,12 @@ func (tx *MsgTx) TxSha() (ShaHash, error) {
|
|||
// Copy creates a deep copy of a transaction so that the original does not get
|
||||
// modified when the copy is manipulated.
|
||||
func (tx *MsgTx) Copy() *MsgTx {
|
||||
// Create new tx and start by copying primitive values.
|
||||
// Create new tx and start by copying primitive values and making space
|
||||
// for the transaction inputs and outputs.
|
||||
newTx := MsgTx{
|
||||
Version: tx.Version,
|
||||
TxIn: make([]*TxIn, 0, len(tx.TxIn)),
|
||||
TxOut: make([]*TxOut, 0, len(tx.TxOut)),
|
||||
LockTime: tx.LockTime,
|
||||
}
|
||||
|
||||
|
@ -181,6 +191,7 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return err
|
||||
}
|
||||
|
||||
msg.TxIn = make([]*TxIn, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
ti := TxIn{}
|
||||
err = readTxIn(r, pver, msg.Version, &ti)
|
||||
|
@ -195,6 +206,7 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error {
|
|||
return err
|
||||
}
|
||||
|
||||
msg.TxOut = make([]*TxOut, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
to := TxOut{}
|
||||
err = readTxOut(r, pver, msg.Version, &to)
|
||||
|
@ -309,7 +321,11 @@ func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 {
|
|||
// to indicate the transaction is valid immediately as opposed to some time in
|
||||
// future.
|
||||
func NewMsgTx() *MsgTx {
|
||||
return &MsgTx{Version: TxVersion}
|
||||
return &MsgTx{
|
||||
Version: TxVersion,
|
||||
TxIn: make([]*TxIn, 0, defaultTxInOutAlloc),
|
||||
TxOut: make([]*TxOut, 0, defaultTxInOutAlloc),
|
||||
}
|
||||
}
|
||||
|
||||
// readOutPoint reads the next sequence of bytes from r as an OutPoint.
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
|
||||
github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37)
|
||||
github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31)
|
||||
github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (27/27)
|
||||
github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25)
|
||||
github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (25/25)
|
||||
github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24)
|
||||
github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24)
|
||||
github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23)
|
||||
github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22)
|
||||
github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20)
|
||||
github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20)
|
||||
github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20)
|
||||
github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20)
|
||||
github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19)
|
||||
github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19)
|
||||
github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18)
|
||||
github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18)
|
||||
github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17)
|
||||
github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (17/17)
|
||||
github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16)
|
||||
github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16)
|
||||
github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (15/15)
|
||||
github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (16/16)
|
||||
github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15)
|
||||
github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15)
|
||||
github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15)
|
||||
github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15)
|
||||
github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15)
|
||||
github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14)
|
||||
github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13)
|
||||
github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13)
|
||||
github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13)
|
||||
github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13)
|
||||
github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14)
|
||||
github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14)
|
||||
github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14)
|
||||
github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14)
|
||||
github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (12/12)
|
||||
github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12)
|
||||
github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12)
|
||||
github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12)
|
||||
github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12)
|
||||
github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11)
|
||||
github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10)
|
||||
github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (11/11)
|
||||
github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10)
|
||||
github.com/conformal/btcwire/message.go discardInput 100.00% (10/10)
|
||||
github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9)
|
||||
github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8)
|
||||
github.com/conformal/btcwire/common.go readVarString 100.00% (8/8)
|
||||
github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8)
|
||||
github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8)
|
||||
github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8)
|
||||
github.com/conformal/btcwire/common.go readVarString 100.00% (8/8)
|
||||
github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7)
|
||||
github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7)
|
||||
github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7)
|
||||
github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7)
|
||||
github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7)
|
||||
github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7)
|
||||
github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7)
|
||||
github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7)
|
||||
|
@ -154,5 +154,5 @@ github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1
|
|||
github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1)
|
||||
github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1)
|
||||
github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1)
|
||||
github.com/conformal/btcwire --------------------------------- 100.00% (932/932)
|
||||
github.com/conformal/btcwire --------------------------------- 100.00% (943/943)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue