github.com/bhojpur/cache@v0.0.4/pkg/pools/pools.go (about)

     1  package pools
     2  
     3  // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved.
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in
    13  // all copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  // THE SOFTWARE.
    22  
    23  // Package pools provides a collection of pools which provide various data
    24  // types with buffers. These can be used to lower the number of memory
    25  // allocations and reuse buffers.
    26  //
    27  // New pools should be added to this package to allow them to be shared across
    28  // packages.
    29  //
    30  // Utility functions which operate on pools should be added to this package to
    31  // allow them to be reused.
    32  
    33  import (
    34  	"bufio"
    35  	"io"
    36  	"sync"
    37  
    38  	"github.com/bhojpur/cache/pkg/ioutils"
    39  )
    40  
    41  const buffer32K = 32 * 1024
    42  
    43  var (
    44  	// BufioReader32KPool is a pool which returns bufio.Reader with a 32K buffer.
    45  	BufioReader32KPool = newBufioReaderPoolWithSize(buffer32K)
    46  	// BufioWriter32KPool is a pool which returns bufio.Writer with a 32K buffer.
    47  	BufioWriter32KPool = newBufioWriterPoolWithSize(buffer32K)
    48  	buffer32KPool      = newBufferPoolWithSize(buffer32K)
    49  )
    50  
    51  // BufioReaderPool is a bufio reader that uses sync.Pool.
    52  type BufioReaderPool struct {
    53  	pool sync.Pool
    54  }
    55  
    56  // newBufioReaderPoolWithSize is unexported because new pools should be
    57  // added here to be shared where required.
    58  func newBufioReaderPoolWithSize(size int) *BufioReaderPool {
    59  	return &BufioReaderPool{
    60  		pool: sync.Pool{
    61  			New: func() interface{} { return bufio.NewReaderSize(nil, size) },
    62  		},
    63  	}
    64  }
    65  
    66  // Get returns a bufio.Reader which reads from r. The buffer size is that of the pool.
    67  func (bufPool *BufioReaderPool) Get(r io.Reader) *bufio.Reader {
    68  	buf := bufPool.pool.Get().(*bufio.Reader)
    69  	buf.Reset(r)
    70  	return buf
    71  }
    72  
    73  // Put puts the bufio.Reader back into the pool.
    74  func (bufPool *BufioReaderPool) Put(b *bufio.Reader) {
    75  	b.Reset(nil)
    76  	bufPool.pool.Put(b)
    77  }
    78  
    79  type bufferPool struct {
    80  	pool sync.Pool
    81  }
    82  
    83  func newBufferPoolWithSize(size int) *bufferPool {
    84  	return &bufferPool{
    85  		pool: sync.Pool{
    86  			New: func() interface{} { s := make([]byte, size); return &s },
    87  		},
    88  	}
    89  }
    90  
    91  func (bp *bufferPool) Get() *[]byte {
    92  	return bp.pool.Get().(*[]byte)
    93  }
    94  
    95  func (bp *bufferPool) Put(b *[]byte) {
    96  	bp.pool.Put(b)
    97  }
    98  
    99  // Copy is a convenience wrapper which uses a buffer to avoid allocation in io.Copy.
   100  func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
   101  	buf := buffer32KPool.Get()
   102  	written, err = io.CopyBuffer(dst, src, *buf)
   103  	buffer32KPool.Put(buf)
   104  	return
   105  }
   106  
   107  // NewReadCloserWrapper returns a wrapper which puts the bufio.Reader back
   108  // into the pool and closes the reader if it's an io.ReadCloser.
   109  func (bufPool *BufioReaderPool) NewReadCloserWrapper(buf *bufio.Reader, r io.Reader) io.ReadCloser {
   110  	return ioutils.NewReadCloserWrapper(r, func() error {
   111  		if readCloser, ok := r.(io.ReadCloser); ok {
   112  			readCloser.Close()
   113  		}
   114  		bufPool.Put(buf)
   115  		return nil
   116  	})
   117  }
   118  
   119  // BufioWriterPool is a bufio writer that uses sync.Pool.
   120  type BufioWriterPool struct {
   121  	pool sync.Pool
   122  }
   123  
   124  // newBufioWriterPoolWithSize is unexported because new pools should be
   125  // added here to be shared where required.
   126  func newBufioWriterPoolWithSize(size int) *BufioWriterPool {
   127  	return &BufioWriterPool{
   128  		pool: sync.Pool{
   129  			New: func() interface{} { return bufio.NewWriterSize(nil, size) },
   130  		},
   131  	}
   132  }
   133  
   134  // Get returns a bufio.Writer which writes to w. The buffer size is that of the pool.
   135  func (bufPool *BufioWriterPool) Get(w io.Writer) *bufio.Writer {
   136  	buf := bufPool.pool.Get().(*bufio.Writer)
   137  	buf.Reset(w)
   138  	return buf
   139  }
   140  
   141  // Put puts the bufio.Writer back into the pool.
   142  func (bufPool *BufioWriterPool) Put(b *bufio.Writer) {
   143  	b.Reset(nil)
   144  	bufPool.pool.Put(b)
   145  }
   146  
   147  // NewWriteCloserWrapper returns a wrapper which puts the bufio.Writer back
   148  // into the pool and closes the writer if it's an io.Writecloser.
   149  func (bufPool *BufioWriterPool) NewWriteCloserWrapper(buf *bufio.Writer, w io.Writer) io.WriteCloser {
   150  	return ioutils.NewWriteCloserWrapper(w, func() error {
   151  		buf.Flush()
   152  		if writeCloser, ok := w.(io.WriteCloser); ok {
   153  			writeCloser.Close()
   154  		}
   155  		bufPool.Put(buf)
   156  		return nil
   157  	})
   158  }