Skip to content

Commit b79fb61

Browse files
authored
mem: use slice capacity instead of length, to determine whether to pool buffers or directly allocate them (#7702) (#7792)
1 parent 54841ef commit b79fb61

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

mem/buffers.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,11 @@ func newBuffer() *buffer {
9292
//
9393
// Note that the backing array of the given data is not copied.
9494
func NewBuffer(data *[]byte, pool BufferPool) Buffer {
95-
if pool == nil || IsBelowBufferPoolingThreshold(len(*data)) {
95+
// Use the buffer's capacity instead of the length, otherwise buffers may
96+
// not be reused under certain conditions. For example, if a large buffer
97+
// is acquired from the pool, but fewer bytes than the buffering threshold
98+
// are written to it, the buffer will not be returned to the pool.
99+
if pool == nil || IsBelowBufferPoolingThreshold(cap(*data)) {
96100
return (SliceBuffer)(*data)
97101
}
98102
b := newBuffer()

mem/buffers_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,33 @@ func (s) TestBuffer_NewBufferRefAndFree(t *testing.T) {
9898
}
9999
}
100100

101+
func (s) TestBuffer_NewBufferHandlesShortBuffers(t *testing.T) {
102+
const threshold = 100
103+
104+
// Update the pooling threshold, since that's what's being tested.
105+
internal.SetBufferPoolingThresholdForTesting.(func(int))(threshold)
106+
t.Cleanup(func() {
107+
internal.SetBufferPoolingThresholdForTesting.(func(int))(0)
108+
})
109+
110+
// Make a pool with a buffer whose capacity is larger than the pooling
111+
// threshold, but whose length is less than the threshold.
112+
b := make([]byte, threshold/2, threshold*2)
113+
pool := &singleBufferPool{
114+
t: t,
115+
data: &b,
116+
}
117+
118+
// Get a Buffer, then free it. If NewBuffer decided that the Buffer
119+
// shouldn't get pooled, Free will be a noop and singleBufferPool will not
120+
// have been updated.
121+
mem.NewBuffer(&b, pool).Free()
122+
123+
if pool.data != nil {
124+
t.Fatalf("Buffer not returned to pool")
125+
}
126+
}
127+
101128
func (s) TestBuffer_FreeAfterFree(t *testing.T) {
102129
buf := newBuffer([]byte("abcd"), mem.NopBufferPool{})
103130
if buf.Len() != 4 {

0 commit comments

Comments
 (0)