sizedbufferpool.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. package bpool
  2. import (
  3. "bytes"
  4. )
  5. // SizedBufferPool implements a pool of bytes.Buffers in the form of a bounded
  6. // channel. Buffers are pre-allocated to the requested size.
  7. type SizedBufferPool struct {
  8. c chan *bytes.Buffer
  9. a int
  10. }
  11. // SizedBufferPool creates a new BufferPool bounded to the given size.
  12. // size defines the number of buffers to be retained in the pool and alloc sets
  13. // the initial capacity of new buffers to minimize calls to make().
  14. //
  15. // The value of alloc should seek to provide a buffer that is representative of
  16. // most data written to the the buffer (i.e. 95th percentile) without being
  17. // overly large (which will increase static memory consumption). You may wish to
  18. // track the capacity of your last N buffers (i.e. using an []int) prior to
  19. // returning them to the pool as input into calculating a suitable alloc value.
  20. func NewSizedBufferPool(size int, alloc int) (bp *SizedBufferPool) {
  21. return &SizedBufferPool{
  22. c: make(chan *bytes.Buffer, size),
  23. a: alloc,
  24. }
  25. }
  26. // Get gets a Buffer from the SizedBufferPool, or creates a new one if none are
  27. // available in the pool. Buffers have a pre-allocated capacity.
  28. func (bp *SizedBufferPool) Get() (b *bytes.Buffer) {
  29. select {
  30. case b = <-bp.c:
  31. // reuse existing buffer
  32. default:
  33. // create new buffer
  34. b = bytes.NewBuffer(make([]byte, 0, bp.a))
  35. }
  36. return
  37. }
  38. // Put returns the given Buffer to the SizedBufferPool.
  39. func (bp *SizedBufferPool) Put(b *bytes.Buffer) {
  40. b.Reset()
  41. // Release buffers over our maximum capacity and re-create a pre-sized
  42. // buffer to replace it.
  43. // Note that the cap(b.Bytes()) provides the capacity from the read off-set
  44. // only, but as we've called b.Reset() the full capacity of the underlying
  45. // byte slice is returned.
  46. if cap(b.Bytes()) > bp.a {
  47. b = bytes.NewBuffer(make([]byte, 0, bp.a))
  48. }
  49. select {
  50. case bp.c <- b:
  51. default: // Discard the buffer if the pool is full.
  52. }
  53. }