aboutsummaryrefslogtreecommitdiff
path: root/internal/bufpool
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-04 08:26:56 +0800
committerGravatar Runxi Yu2026-03-04 08:59:53 +0800
commitab7501be34032fb9e5c48726a68ae90a917af9eb (patch)
tree20d005647569befea8133e953c3270e8fd2a2a5b /internal/bufpool
parent*: gofumpt (diff)
signatureNo signature
*: Lint
Diffstat (limited to 'internal/bufpool')
-rw-r--r--internal/bufpool/buffers.go17
-rw-r--r--internal/bufpool/buffers_test.go9
2 files changed, 26 insertions, 0 deletions
diff --git a/internal/bufpool/buffers.go b/internal/bufpool/buffers.go
index a5c27b67..91e30a31 100644
--- a/internal/bufpool/buffers.go
+++ b/internal/bufpool/buffers.go
@@ -62,9 +62,11 @@ var bufferPools = func() []sync.Pool {
capCopy := classCap
pools[i].New = func() any {
buf := make([]byte, 0, capCopy)
+
return &buf
}
}
+
return pools
}()
@@ -80,9 +82,11 @@ func Borrow(capHint int) Buffer {
if capHint < DefaultBufferCap {
capHint = DefaultBufferCap
}
+
classIdx, classCap, pooled := classFor(capHint)
if !pooled {
newBuf := make([]byte, 0, capHint)
+
return Buffer{buf: newBuf, pool: unpooled}
}
//nolint:forcetypeassert
@@ -90,7 +94,9 @@ func Borrow(capHint int) Buffer {
if cap(*buf) < classCap {
*buf = make([]byte, 0, classCap)
}
+
slice := (*buf)[:0]
+
return Buffer{buf: slice, pool: poolIndex(classIdx)} //#nosec G115
}
@@ -110,6 +116,7 @@ func (buf *Buffer) Resize(n int) {
if n < 0 {
n = 0
}
+
buf.ensureCapacity(n)
buf.buf = buf.buf[:n]
}
@@ -122,6 +129,7 @@ func (buf *Buffer) Append(src []byte) {
if len(src) == 0 {
return
}
+
start := len(buf.buf)
buf.ensureCapacity(start + len(src))
buf.buf = buf.buf[:start+len(src)]
@@ -144,6 +152,7 @@ func (buf *Buffer) Release() {
if buf.buf == nil {
return
}
+
buf.returnToPool()
buf.buf = nil
buf.pool = unpooled
@@ -157,20 +166,26 @@ func (buf *Buffer) ensureCapacity(needed int) {
if cap(buf.buf) >= needed {
return
}
+
classIdx, classCap, pooled := classFor(needed)
+
var newBuf []byte
+
if pooled {
//nolint:forcetypeassert
raw := bufferPools[classIdx].Get().(*[]byte)
if cap(*raw) < classCap {
*raw = make([]byte, 0, classCap)
}
+
newBuf = (*raw)[:len(buf.buf)]
} else {
newBuf = make([]byte, len(buf.buf), classCap)
}
+
copy(newBuf, buf.buf)
buf.returnToPool()
+
buf.buf = newBuf
if pooled {
buf.pool = poolIndex(classIdx) //#nosec G115
@@ -185,6 +200,7 @@ func classFor(size int) (idx, classCap int, ok bool) {
return i, class, true
}
}
+
return -1, size, false
}
@@ -192,6 +208,7 @@ func (buf *Buffer) returnToPool() {
if buf.pool == unpooled {
return
}
+
tmp := buf.buf[:0]
bufferPools[int(buf.pool)].Put(&tmp)
}
diff --git a/internal/bufpool/buffers_test.go b/internal/bufpool/buffers_test.go
index 70861d33..224fa98c 100644
--- a/internal/bufpool/buffers_test.go
+++ b/internal/bufpool/buffers_test.go
@@ -15,19 +15,23 @@ func TestBorrowBufferResizeAndAppend(t *testing.T) {
b.Append([]byte("alpha"))
b.Append([]byte("beta"))
+
if got := string(b.Bytes()); got != "alphabeta" {
t.Fatalf("unexpected contents: %q", got)
}
b.Resize(3)
+
if got := string(b.Bytes()); got != "alp" {
t.Fatalf("resize shrink mismatch: %q", got)
}
b.Resize(8)
+
if len(b.Bytes()) != 8 {
t.Fatalf("expected len 8 after grow, got %d", len(b.Bytes()))
}
+
if prefix := string(b.Bytes()[:3]); prefix != "alp" {
t.Fatalf("prefix lost after grow: %q", prefix)
}
@@ -39,6 +43,7 @@ func TestBorrowBufferRelease(t *testing.T) {
b := Borrow(DefaultBufferCap / 2)
b.Append([]byte("data"))
b.Release()
+
if b.buf != nil {
t.Fatal("expected buffer cleared after release")
}
@@ -59,9 +64,11 @@ func TestBorrowUsesLargerPools(t *testing.T) {
if b.pool != poolIndex(classIdx) {
t.Fatalf("expected pooled buffer in class %d, got %d", classIdx, b.pool)
}
+
if cap(b.buf) != classCap {
t.Fatalf("expected capacity %d, got %d", classCap, cap(b.buf))
}
+
b.Release()
b2 := Borrow(request)
@@ -70,6 +77,7 @@ func TestBorrowUsesLargerPools(t *testing.T) {
if b2.pool != poolIndex(classIdx) {
t.Fatalf("expected pooled buffer in class %d on reuse, got %d", classIdx, b2.pool)
}
+
if cap(b2.buf) != classCap {
t.Fatalf("expected capacity %d on reuse, got %d", classCap, cap(b2.buf))
}
@@ -82,6 +90,7 @@ func TestGrowingBufferStaysPooled(t *testing.T) {
defer b.Release()
b.Append(make([]byte, DefaultBufferCap*3))
+
if b.pool == unpooled {
t.Fatal("buffer should stay pooled after growth within limit")
}