diff --git a/bytebuffer.go b/bytebuffer.go index 9edf992..f7ce7bf 100644 --- a/bytebuffer.go +++ b/bytebuffer.go @@ -6,7 +6,7 @@ package bytebufferpool // ByteBuffer may be used with functions appending data to the given []byte // slice. See example code for details. // -// Use Acquire for obtaining an empty byte buffer. +// Use Get for obtaining an empty byte buffer. type ByteBuffer struct { // B is a byte buffer to use in append-like workloads. @@ -41,21 +41,21 @@ func (b *ByteBuffer) Reset() { b.B = b.B[:0] } -// Acquire returns an empty byte buffer from the pool. +// Get returns an empty byte buffer from the pool. // -// Acquired byte buffer may be returned to the pool via Release call. +// Getd byte buffer may be returned to the pool via Put call. // This reduces the number of memory allocations required for byte buffer // management. -func Acquire() *ByteBuffer { - return defaultByteBufferPool.Acquire() +func Get() *ByteBuffer { + return defaultPool.Get() } -// Release returns byte buffer to the pool. +// Put returns byte buffer to the pool. // // ByteBuffer.B mustn't be touched after returning it to the pool. // Otherwise data races will occur. -func Release(b *ByteBuffer) { - defaultByteBufferPool.Release(b) +func Put(b *ByteBuffer) { + defaultPool.Put(b) } -var defaultByteBufferPool byteBufferPool +var defaultPool Pool diff --git a/bytebuffer_example_test.go b/bytebuffer_example_test.go index 1b7aa4a..1cbaaf5 100644 --- a/bytebuffer_example_test.go +++ b/bytebuffer_example_test.go @@ -7,7 +7,7 @@ import ( ) func ExampleByteBuffer() { - bb := bytebufferpool.Acquire() + bb := bytebufferpool.Get() bb.WriteString("first line\n") bb.Write([]byte("second line\n")) @@ -17,5 +17,5 @@ func ExampleByteBuffer() { // It is safe to release byte buffer now, since it is // no longer used. - bytebufferpool.Release(bb) + bytebufferpool.Put(bb) } diff --git a/bytebuffer_test.go b/bytebuffer_test.go index d9ab904..7b98815 100644 --- a/bytebuffer_test.go +++ b/bytebuffer_test.go @@ -6,16 +6,16 @@ import ( "time" ) -func TestByteBufferAcquireReleaseSerial(t *testing.T) { - testByteBufferAcquireRelease(t) +func TestByteBufferGetPutSerial(t *testing.T) { + testByteBufferGetPut(t) } -func TestByteBufferAcquireReleaseConcurrent(t *testing.T) { +func TestByteBufferGetPutConcurrent(t *testing.T) { concurrency := 10 ch := make(chan struct{}, concurrency) for i := 0; i < concurrency; i++ { go func() { - testByteBufferAcquireRelease(t) + testByteBufferGetPut(t) ch <- struct{}{} }() } @@ -29,15 +29,15 @@ func TestByteBufferAcquireReleaseConcurrent(t *testing.T) { } } -func testByteBufferAcquireRelease(t *testing.T) { +func testByteBufferGetPut(t *testing.T) { for i := 0; i < 10; i++ { expectedS := fmt.Sprintf("num %d", i) - b := Acquire() + b := Get() b.B = append(b.B, "num "...) b.B = append(b.B, fmt.Sprintf("%d", i)...) if string(b.B) != expectedS { t.Fatalf("unexpected result: %q. Expecting %q", b.B, expectedS) } - Release(b) + Put(b) } } diff --git a/pool.go b/pool.go index cb41bb9..ccbf66a 100644 --- a/pool.go +++ b/pool.go @@ -17,7 +17,12 @@ const ( maxPercentile = 0.95 ) -type byteBufferPool struct { +// Pool represents byte buffer pool. +// +// Distinct pools may be used for distinct types of byte buffers. +// Properly determined byte buffer types with their own pools may help reducing +// memory waste. +type Pool struct { calls [steps]uint64 calibrating uint64 @@ -27,7 +32,11 @@ type byteBufferPool struct { pool sync.Pool } -func (p *byteBufferPool) Acquire() *ByteBuffer { +// Get returns new byte buffer with zero length. +// +// The byte buffer may be returned to the pool via Put after the use +// in order to minimize GC overhead. +func (p *Pool) Get() *ByteBuffer { v := p.pool.Get() if v != nil { return v.(*ByteBuffer) @@ -37,7 +46,10 @@ func (p *byteBufferPool) Acquire() *ByteBuffer { } } -func (p *byteBufferPool) Release(b *ByteBuffer) { +// Put releases byte buffer obtained via Get to the pool. +// +// The bufer mustn't be accessed after returning to the pool. +func (p *Pool) Put(b *ByteBuffer) { idx := index(len(b.B)) if atomic.AddUint64(&p.calls[idx], 1) > calibrateCallsThreshold { @@ -51,7 +63,7 @@ func (p *byteBufferPool) Release(b *ByteBuffer) { } } -func (p *byteBufferPool) calibrate() { +func (p *Pool) calibrate() { if !atomic.CompareAndSwapUint64(&p.calibrating, 0, 1) { return } diff --git a/pool_test.go b/pool_test.go index a8157a9..6d3bcb8 100644 --- a/pool_test.go +++ b/pool_test.go @@ -36,7 +36,7 @@ func TestPoolCalibrate(t *testing.T) { if i%15 == 0 { n = rand.Intn(15234) } - testAcquireRelease(t, n) + testGetPut(t, n) } } @@ -66,23 +66,23 @@ func testPoolVariousSizes(t *testing.T) { for i := 0; i < steps+1; i++ { n := (1 << uint32(i)) - testAcquireRelease(t, n) - testAcquireRelease(t, n+1) - testAcquireRelease(t, n-1) + testGetPut(t, n) + testGetPut(t, n+1) + testGetPut(t, n-1) for j := 0; j < 10; j++ { - testAcquireRelease(t, j+n) + testGetPut(t, j+n) } } } -func testAcquireRelease(t *testing.T, n int) { - bb := Acquire() +func testGetPut(t *testing.T, n int) { + bb := Get() if len(bb.B) > 0 { t.Fatalf("non-empty byte buffer returned from acquire") } bb.B = allocNBytes(bb.B, n) - Release(bb) + Put(bb) } func allocNBytes(dst []byte, n int) []byte {