diff --git a/tm2/pkg/amino/amino.go b/tm2/pkg/amino/amino.go index 262f5d9a54e..bcd52e97ebf 100644 --- a/tm2/pkg/amino/amino.go +++ b/tm2/pkg/amino/amino.go @@ -219,7 +219,11 @@ func (cdc *Codec) MarshalSized(o interface{}) ([]byte, error) { cdc.doAutoseal() // Write the bytes here. - buf := new(bytes.Buffer) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() // Write the bz without length-prefixing. bz, err := cdc.Marshal(o) @@ -239,7 +243,7 @@ func (cdc *Codec) MarshalSized(o interface{}) ([]byte, error) { return nil, err } - return buf.Bytes(), nil + return copyBytes(buf.Bytes()), nil } // MarshalSizedWriter writes the bytes as would be returned from @@ -271,7 +275,11 @@ func (cdc *Codec) MarshalAnySized(o interface{}) ([]byte, error) { cdc.doAutoseal() // Write the bytes here. - buf := new(bytes.Buffer) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() // Write the bz without length-prefixing. bz, err := cdc.MarshalAny(o) @@ -291,7 +299,7 @@ func (cdc *Codec) MarshalAnySized(o interface{}) ([]byte, error) { return nil, err } - return buf.Bytes(), nil + return copyBytes(buf.Bytes()), nil } func (cdc *Codec) MustMarshalAnySized(o interface{}) []byte { @@ -357,7 +365,12 @@ func (cdc *Codec) MarshalReflect(o interface{}) ([]byte, error) { // Encode Amino:binary bytes. var bz []byte - buf := new(bytes.Buffer) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() + rt := rv.Type() info, err := cdc.getTypeInfoWLock(rt) if err != nil { @@ -377,7 +390,7 @@ func (cdc *Codec) MarshalReflect(o interface{}) ([]byte, error) { if err = cdc.writeFieldIfNotEmpty(buf, 1, info, FieldOptions{}, FieldOptions{}, rv, writeEmpty); err != nil { return nil, err } - bz = buf.Bytes() + bz = copyBytes(buf.Bytes()) } else { // The passed in BinFieldNum is only relevant for when the type is to // be encoded unpacked (elements are Typ3_ByteLength). In that case, @@ -387,7 +400,7 @@ func (cdc *Codec) MarshalReflect(o interface{}) ([]byte, error) { if err != nil { return nil, err } - bz = buf.Bytes() + bz = copyBytes(buf.Bytes()) } // If bz is empty, prefer nil. if len(bz) == 0 { @@ -443,16 +456,26 @@ func (cdc *Codec) MarshalAny(o interface{}) ([]byte, error) { } // Encode as interface. - buf := new(bytes.Buffer) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() err = cdc.encodeReflectBinaryInterface(buf, iinfo, reflect.ValueOf(&ivar).Elem(), FieldOptions{}, true) if err != nil { return nil, err } - bz := buf.Bytes() + bz := copyBytes(buf.Bytes()) return bz, nil } +func copyBytes(bz []byte) []byte { + cp := make([]byte, len(bz)) + copy(cp, bz) + return cp +} + // Panics if error. func (cdc *Codec) MustMarshalAny(o interface{}) []byte { bz, err := cdc.MarshalAny(o) @@ -764,7 +787,11 @@ func (cdc *Codec) JSONMarshal(o interface{}) ([]byte, error) { return []byte("null"), nil } rt := rv.Type() - w := new(bytes.Buffer) + w := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + w.Reset() + poolBytesBuffer.Put(w) + }() info, err := cdc.getTypeInfoWLock(rt) if err != nil { return nil, err @@ -772,7 +799,8 @@ func (cdc *Codec) JSONMarshal(o interface{}) ([]byte, error) { if err = cdc.encodeReflectJSON(w, info, rv, FieldOptions{}); err != nil { return nil, err } - return w.Bytes(), nil + + return copyBytes(w.Bytes()), nil } func (cdc *Codec) MarshalJSONAny(o interface{}) ([]byte, error) { @@ -802,12 +830,17 @@ func (cdc *Codec) MarshalJSONAny(o interface{}) ([]byte, error) { } // Encode as interface. - buf := new(bytes.Buffer) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() + err = cdc.encodeReflectJSONInterface(buf, iinfo, reflect.ValueOf(&ivar).Elem(), FieldOptions{}) if err != nil { return nil, err } - bz := buf.Bytes() + bz := copyBytes(buf.Bytes()) return bz, nil } @@ -863,12 +896,17 @@ func (cdc *Codec) MarshalJSONIndent(o interface{}, prefix, indent string) ([]byt if err != nil { return nil, err } - var out bytes.Buffer - err = json.Indent(&out, bz, prefix, indent) + out := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + out.Reset() + poolBytesBuffer.Put(out) + }() + + err = json.Indent(out, bz, prefix, indent) if err != nil { return nil, err } - return out.Bytes(), nil + return copyBytes(out.Bytes()), nil } // ---------------------------------------- diff --git a/tm2/pkg/amino/binary_encode.go b/tm2/pkg/amino/binary_encode.go index 426cc520604..6f7adc6a62d 100644 --- a/tm2/pkg/amino/binary_encode.go +++ b/tm2/pkg/amino/binary_encode.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "reflect" + "sync" ) const beOptionByte = 0x01 @@ -209,6 +210,10 @@ func (cdc *Codec) encodeReflectBinary(w io.Writer, info *TypeInfo, rv reflect.Va return err } +var poolBytesBuffer = &sync.Pool{ + New: func() any { return new(bytes.Buffer) }, +} + func (cdc *Codec) encodeReflectBinaryInterface(w io.Writer, iinfo *TypeInfo, rv reflect.Value, fopts FieldOptions, bare bool, ) (err error) { @@ -250,7 +255,12 @@ func (cdc *Codec) encodeReflectBinaryInterface(w io.Writer, iinfo *TypeInfo, rv // For Proto3 compatibility, encode interfaces as google.protobuf.Any // Write field #1, TypeURL - buf := bytes.NewBuffer(nil) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() + { fnum := uint32(1) err = encodeFieldNumberAndTyp3(buf, fnum, Typ3ByteLength) @@ -269,7 +279,12 @@ func (cdc *Codec) encodeReflectBinaryInterface(w io.Writer, iinfo *TypeInfo, rv { // google.protobuf.Any values must be a struct, or an unpacked list which // is indistinguishable from a struct. - buf2 := bytes.NewBuffer(nil) + buf2 := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf2.Reset() + poolBytesBuffer.Put(buf2) + }() + if !cinfo.IsStructOrUnpacked(fopts) { writeEmpty := false // Encode with an implicit struct, with a single field with number 1. @@ -356,7 +371,11 @@ func (cdc *Codec) encodeReflectBinaryList(w io.Writer, info *TypeInfo, rv reflec // Proto3 byte-length prefixing incurs alloc cost on the encoder. // Here we incur it for unpacked form for ease of dev. - buf := bytes.NewBuffer(nil) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() // If elem is not already a ByteLength type, write in packed form. // This is a Proto wart due to Proto backwards compatibility issues. @@ -431,9 +450,15 @@ func (cdc *Codec) encodeReflectBinaryList(w io.Writer, info *TypeInfo, rv reflec // form) are represented as lists of implicit structs. if writeImplicit { // Write field key for Value field of implicit struct. - buf2 := new(bytes.Buffer) + buf2 := poolBytesBuffer.Get().(*bytes.Buffer) + buf2Done := func() { + buf2.Reset() + poolBytesBuffer.Put(buf2) + } + err = encodeFieldNumberAndTyp3(buf2, 1, Typ3ByteLength) if err != nil { + buf2Done() return } // Write field value of implicit struct to buf2. @@ -441,10 +466,12 @@ func (cdc *Codec) encodeReflectBinaryList(w io.Writer, info *TypeInfo, rv reflec efopts.BinFieldNum = 0 // dontcare err = cdc.encodeReflectBinary(buf2, einfo, derv, efopts, false, 0) if err != nil { + buf2Done() return } // Write implicit struct to buf. err = EncodeByteSlice(buf, buf2.Bytes()) + buf2Done() if err != nil { return } @@ -497,7 +524,11 @@ func (cdc *Codec) encodeReflectBinaryStruct(w io.Writer, info *TypeInfo, rv refl // Proto3 incurs a cost in writing non-root structs. // Here we incur it for root structs as well for ease of dev. - buf := bytes.NewBuffer(nil) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() for _, field := range info.Fields { // Get type info for field. diff --git a/tm2/pkg/amino/codec.go b/tm2/pkg/amino/codec.go index 3fa7634e3ad..c3952468d84 100644 --- a/tm2/pkg/amino/codec.go +++ b/tm2/pkg/amino/codec.go @@ -113,7 +113,12 @@ func (info *TypeInfo) String() string { // before it's fully populated. return "" } - buf := new(bytes.Buffer) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() + buf.Write([]byte("TypeInfo{")) buf.Write([]byte(fmt.Sprintf("Type:%v,", info.Type))) if info.ConcreteInfo.Registered { diff --git a/tm2/pkg/amino/json_encode.go b/tm2/pkg/amino/json_encode.go index 113c3486565..3cbd5e2f705 100644 --- a/tm2/pkg/amino/json_encode.go +++ b/tm2/pkg/amino/json_encode.go @@ -156,7 +156,12 @@ func (cdc *Codec) encodeReflectJSONInterface(w io.Writer, iinfo *TypeInfo, rv re } // Write Value to buffer - buf := new(bytes.Buffer) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() + cdc.encodeReflectJSON(buf, cinfo, crv, fopts) value := buf.Bytes() if len(value) == 0 { diff --git a/tm2/pkg/amino/wellknown.go b/tm2/pkg/amino/wellknown.go index 7720c2894d9..2f5d9ef65e2 100644 --- a/tm2/pkg/amino/wellknown.go +++ b/tm2/pkg/amino/wellknown.go @@ -342,7 +342,12 @@ func encodeReflectBinaryWellKnown(w io.Writer, info *TypeInfo, rv reflect.Value, } // Maybe recurse with length-prefixing. if !bare { - buf := bytes.NewBuffer(nil) + buf := poolBytesBuffer.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + poolBytesBuffer.Put(buf) + }() + ok, err = encodeReflectBinaryWellKnown(buf, info, rv, fopts, true) if err != nil { return false, err