2adfb3b56a
The current code involves a ton of small allocations which is harsh on the garbage collector and in turn causes a lot of addition runtime overhead both in terms of additional memory and processing time. In order to improve the situation, this drasticially reduces the number of allocations by creating contiguous slices of objects and deserializing into them. Since the final data structures consist of slices of pointers to the objects, they are constructed by pointing them into the appropriate offset of the contiguous slice. This could be improved upon even further by converting all of the data structures provided the wire package to be slices of contiguous objects directly, however that would be a major breaking API change and would end up requiring updating a lot more code in every caller. I do think that ultimately the API should be changed, but the changes in this commit already makes a massive difference and it doesn't require touching any of the callers, so it is a good place to begin. The following is a before and after comparison of the allocations with the benchmarks that did not change removed: benchmark old allocs new allocs delta ----------------------------------------------------------- DeserializeTxLarge 16715 11146 -33.32% DecodeGetHeaders 501 2 -99.60% DecodeHeaders 2001 2 -99.90% DecodeGetBlocks 501 2 -99.60% DecodeAddr 3001 2002 -33.29% DecodeInv 50003 3 -99.99% DecodeNotFound 50002 3 -99.99% DecodeMerkleBlock 107 3 -97.20%
143 lines
4.2 KiB
Go
143 lines
4.2 KiB
Go
// Copyright (c) 2013-2015 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package wire
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// MaxAddrPerMsg is the maximum number of addresses that can be in a single
|
|
// bitcoin addr message (MsgAddr).
|
|
const MaxAddrPerMsg = 1000
|
|
|
|
// MsgAddr implements the Message interface and represents a bitcoin
|
|
// addr message. It is used to provide a list of known active peers on the
|
|
// network. An active peer is considered one that has transmitted a message
|
|
// within the last 3 hours. Nodes which have not transmitted in that time
|
|
// frame should be forgotten. Each message is limited to a maximum number of
|
|
// addresses, which is currently 1000. As a result, multiple messages must
|
|
// be used to relay the full list.
|
|
//
|
|
// Use the AddAddress function to build up the list of known addresses when
|
|
// sending an addr message to another peer.
|
|
type MsgAddr struct {
|
|
AddrList []*NetAddress
|
|
}
|
|
|
|
// AddAddress adds a known active peer to the message.
|
|
func (msg *MsgAddr) AddAddress(na *NetAddress) error {
|
|
if len(msg.AddrList)+1 > MaxAddrPerMsg {
|
|
str := fmt.Sprintf("too many addresses in message [max %v]",
|
|
MaxAddrPerMsg)
|
|
return messageError("MsgAddr.AddAddress", str)
|
|
}
|
|
|
|
msg.AddrList = append(msg.AddrList, na)
|
|
return nil
|
|
}
|
|
|
|
// AddAddresses adds multiple known active peers to the message.
|
|
func (msg *MsgAddr) AddAddresses(netAddrs ...*NetAddress) error {
|
|
for _, na := range netAddrs {
|
|
err := msg.AddAddress(na)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ClearAddresses removes all addresses from the message.
|
|
func (msg *MsgAddr) ClearAddresses() {
|
|
msg.AddrList = []*NetAddress{}
|
|
}
|
|
|
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
|
// This is part of the Message interface implementation.
|
|
func (msg *MsgAddr) BtcDecode(r io.Reader, pver uint32) error {
|
|
count, err := ReadVarInt(r, pver)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Limit to max addresses per message.
|
|
if count > MaxAddrPerMsg {
|
|
str := fmt.Sprintf("too many addresses for message "+
|
|
"[count %v, max %v]", count, MaxAddrPerMsg)
|
|
return messageError("MsgAddr.BtcDecode", str)
|
|
}
|
|
|
|
addrList := make([]NetAddress, count)
|
|
msg.AddrList = make([]*NetAddress, 0, count)
|
|
for i := uint64(0); i < count; i++ {
|
|
na := &addrList[i]
|
|
err := readNetAddress(r, pver, na, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
msg.AddAddress(na)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
|
// This is part of the Message interface implementation.
|
|
func (msg *MsgAddr) BtcEncode(w io.Writer, pver uint32) error {
|
|
// Protocol versions before MultipleAddressVersion only allowed 1 address
|
|
// per message.
|
|
count := len(msg.AddrList)
|
|
if pver < MultipleAddressVersion && count > 1 {
|
|
str := fmt.Sprintf("too many addresses for message of "+
|
|
"protocol version %v [count %v, max 1]", pver, count)
|
|
return messageError("MsgAddr.BtcEncode", str)
|
|
|
|
}
|
|
if count > MaxAddrPerMsg {
|
|
str := fmt.Sprintf("too many addresses for message "+
|
|
"[count %v, max %v]", count, MaxAddrPerMsg)
|
|
return messageError("MsgAddr.BtcEncode", str)
|
|
}
|
|
|
|
err := WriteVarInt(w, pver, uint64(count))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, na := range msg.AddrList {
|
|
err = writeNetAddress(w, pver, na, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Command returns the protocol command string for the message. This is part
|
|
// of the Message interface implementation.
|
|
func (msg *MsgAddr) Command() string {
|
|
return CmdAddr
|
|
}
|
|
|
|
// MaxPayloadLength returns the maximum length the payload can be for the
|
|
// receiver. This is part of the Message interface implementation.
|
|
func (msg *MsgAddr) MaxPayloadLength(pver uint32) uint32 {
|
|
if pver < MultipleAddressVersion {
|
|
// Num addresses (varInt) + a single net addresses.
|
|
return MaxVarIntPayload + maxNetAddressPayload(pver)
|
|
}
|
|
|
|
// Num addresses (varInt) + max allowed addresses.
|
|
return MaxVarIntPayload + (MaxAddrPerMsg * maxNetAddressPayload(pver))
|
|
}
|
|
|
|
// NewMsgAddr returns a new bitcoin addr message that conforms to the
|
|
// Message interface. See MsgAddr for details.
|
|
func NewMsgAddr() *MsgAddr {
|
|
return &MsgAddr{
|
|
AddrList: make([]*NetAddress, 0, MaxAddrPerMsg),
|
|
}
|
|
}
|