Skip to content

Commit caa667f

Browse files
Merge pull request #1068 from mauidude/reduce-allocations
perf(col_str): Reduce heap allocations
2 parents 4fc5f28 + 1bdde09 commit caa667f

File tree

3 files changed

+36
-22
lines changed

3 files changed

+36
-22
lines changed

proto/buffer.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ func (b *Buffer) Reader() *Reader {
1919

2020
// Ensure Buf length.
2121
func (b *Buffer) Ensure(n int) {
22-
b.Buf = append(b.Buf[:0], make([]byte, n)...)
22+
if cap(b.Buf) < n {
23+
b.Buf = make([]byte, n)
24+
} else {
25+
b.Buf = b.Buf[:n] // Set length to n (zeros not guaranteed)
26+
}
2327
}
2428

2529
// Encoder implements encoding to Buffer.
@@ -67,8 +71,8 @@ func (b *Buffer) PutRaw(v []byte) {
6771

6872
// PutUVarInt encodes x as uvarint.
6973
func (b *Buffer) PutUVarInt(x uint64) {
70-
buf := make([]byte, binary.MaxVarintLen64)
71-
n := binary.PutUvarint(buf, x)
74+
buf := [binary.MaxVarintLen64]byte{}
75+
n := binary.PutUvarint(buf[:], x)
7276
b.Buf = append(b.Buf, buf[:n]...)
7377
}
7478

@@ -98,27 +102,27 @@ func (b *Buffer) PutUInt8(x uint8) {
98102
}
99103

100104
func (b *Buffer) PutUInt16(x uint16) {
101-
buf := make([]byte, 16/8)
102-
binary.LittleEndian.PutUint16(buf, x)
103-
b.Buf = append(b.Buf, buf...)
105+
buf := [16 / 8]byte{}
106+
binary.LittleEndian.PutUint16(buf[:], x)
107+
b.Buf = append(b.Buf, buf[:]...)
104108
}
105109

106110
func (b *Buffer) PutUInt32(x uint32) {
107-
buf := make([]byte, 32/8)
108-
binary.LittleEndian.PutUint32(buf, x)
109-
b.Buf = append(b.Buf, buf...)
111+
buf := [32 / 8]byte{}
112+
binary.LittleEndian.PutUint32(buf[:], x)
113+
b.Buf = append(b.Buf, buf[:]...)
110114
}
111115

112116
func (b *Buffer) PutUInt64(x uint64) {
113-
buf := make([]byte, 64/8)
114-
binary.LittleEndian.PutUint64(buf, x)
115-
b.Buf = append(b.Buf, buf...)
117+
buf := [64 / 8]byte{}
118+
binary.LittleEndian.PutUint64(buf[:], x)
119+
b.Buf = append(b.Buf, buf[:]...)
116120
}
117121

118122
func (b *Buffer) PutUInt128(x UInt128) {
119-
buf := make([]byte, 128/8)
120-
binPutUInt128(buf, x)
121-
b.Buf = append(b.Buf, buf...)
123+
buf := [128 / 8]byte{}
124+
binPutUInt128(buf[:], x)
125+
b.Buf = append(b.Buf, buf[:]...)
122126
}
123127

124128
func (b *Buffer) PutInt8(v int8) {

proto/col_str.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,22 +68,27 @@ func (c *ColStr) Reset() {
6868

6969
// EncodeColumn encodes String rows to *Buffer.
7070
func (c ColStr) EncodeColumn(b *Buffer) {
71-
buf := make([]byte, binary.MaxVarintLen64)
71+
var buf [binary.MaxVarintLen64]byte
7272
for _, p := range c.Pos {
73-
n := binary.PutUvarint(buf, uint64(p.End-p.Start))
73+
length := uint64(p.End - p.Start)
74+
75+
// Encode to temp buffer first
76+
n := binary.PutUvarint(buf[:], length)
77+
78+
// Append only the bytes we need
7479
b.Buf = append(b.Buf, buf[:n]...)
7580
b.Buf = append(b.Buf, c.Buf[p.Start:p.End]...)
7681
}
7782
}
7883

7984
// WriteColumn writes String rows to *Writer.
8085
func (c ColStr) WriteColumn(w *Writer) {
81-
buf := make([]byte, binary.MaxVarintLen64)
86+
var buf [binary.MaxVarintLen64]byte
8287
// Writing values from c.Buf directly might improve performance if [ColStr] contains a few rows of very long strings.
8388
// However, most of the time it is quite opposite, so we copy data.
8489
w.ChainBuffer(func(b *Buffer) {
8590
for _, p := range c.Pos {
86-
n := binary.PutUvarint(buf, uint64(p.End-p.Start))
91+
n := binary.PutUvarint(buf[:], uint64(p.End-p.Start))
8792
b.PutRaw(buf[:n])
8893
b.PutRaw(c.Buf[p.Start:p.End])
8994
}

proto/reader.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,17 @@ func (r *Reader) StrBytes() ([]byte, error) {
135135

136136
// Str decodes string.
137137
func (r *Reader) Str() (string, error) {
138-
s, err := r.StrBytes()
138+
defer r.b.Reset()
139+
140+
// call StrRaw instead of StrBytes and converting
141+
// so we can avoid a second allocation and copy of
142+
// the str/[]byte data
143+
str, err := r.StrRaw()
139144
if err != nil {
140-
return "", errors.Wrap(err, "bytes")
145+
return "", errors.Wrap(err, "raw")
141146
}
142147

143-
return string(s), err
148+
return string(str), err
144149
}
145150

146151
// Int decodes uvarint as int.

0 commit comments

Comments
 (0)