| Index: common/sync/bufferpool/buffer_pool.go
|
| diff --git a/common/sync/bufferpool/buffer_pool.go b/common/sync/bufferpool/buffer_pool.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..510b13e9308bb27d98871fd7807afd234b6d51af
|
| --- /dev/null
|
| +++ b/common/sync/bufferpool/buffer_pool.go
|
| @@ -0,0 +1,75 @@
|
| +// Copyright 2016 The LUCI Authors. All rights reserved.
|
| +// Use of this source code is governed under the Apache License, Version 2.0
|
| +// that can be found in the LICENSE file.
|
| +
|
| +// Package bufferpool implements a pool of bytes.Buffer instances backed by
|
| +// a sync.Pool. The goal of using a buffer pool is that, in exchange for some
|
| +// locking overhead, the user can avoid iteratively reallocating buffers for
|
| +// frequently used purposes.
|
| +//
|
| +// Ideal usage of bufferpool is with like-purposed buffers in order to encourage
|
| +// the pool to contain buffers sized to that specific purpose. If this is
|
| +// correctly implemented, the buffers in the pool should generally come into
|
| +// existence, grow to the purpose's size need, and then remain there without
|
| +// further allocation.
|
| +//
|
| +// An overly-broad-purposed pool, on the other hand, will have its buffers grow
|
| +// to max(purpose...) size and consequently contain more large buffers than
|
| +// necessary.
|
| +package bufferpool
|
| +
|
| +import (
|
| + "bytes"
|
| + "sync"
|
| +)
|
| +
|
| +// P is a pool of buffers. The zero value is an initialized but empty pool.
|
| +//
|
| +// P must be passed around as reference, not value.
|
| +type P struct {
|
| + pool sync.Pool
|
| +}
|
| +
|
| +// Get returns a Buffer. When the caller is finished with the Buffer, they
|
| +// should call Release to return it to its pool.
|
| +func (p *P) Get() *Buffer {
|
| + buf, ok := p.pool.Get().(*bytes.Buffer)
|
| + if !ok {
|
| + buf = &bytes.Buffer{}
|
| + }
|
| +
|
| + return &Buffer{
|
| + Buffer: buf,
|
| + p: p,
|
| + }
|
| +}
|
| +
|
| +// Buffer is a bytes.Buffer that is bound to a pool. It should not be used
|
| +// directly, but rather obtained through calling Get on a P instance.
|
| +type Buffer struct {
|
| + *bytes.Buffer
|
| +
|
| + p *P
|
| +}
|
| +
|
| +// Clone clones the contents of the buffer's Bytes, returning an indepdent
|
| +// duplicate []byte.
|
| +func (b *Buffer) Clone() []byte {
|
| + return append([]byte(nil), b.Bytes()...)
|
| +}
|
| +
|
| +// Release returns this Buffer to its pool.
|
| +//
|
| +// After calling Release, no accesses may be made to b or its internal data.
|
| +// If its data is to be retained, it must be cloned prior to Release (see
|
| +// Clone).
|
| +func (b *Buffer) Release() {
|
| + p := b.p
|
| + if p == nil {
|
| + panic("double Release")
|
| + }
|
| +
|
| + b.p = nil
|
| + b.Reset()
|
| + p.pool.Put(b.Buffer)
|
| +}
|
|
|