...

Source file src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go

Documentation: github.com/syndtr/goleveldb/leveldb/util

     1  // Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
     2  // All rights reserved.
     3  //
     4  // Use of this source code is governed by a BSD-style license that can be
     5  // found in the LICENSE file.
     6  
     7  package util
     8  
     9  import (
    10  	"fmt"
    11  	"sync"
    12  	"sync/atomic"
    13  )
    14  
    15  // BufferPool is a 'buffer pool'.
    16  type BufferPool struct {
    17  	pool     [6]sync.Pool
    18  	baseline [5]int
    19  
    20  	get     uint32
    21  	put     uint32
    22  	less    uint32
    23  	equal   uint32
    24  	greater uint32
    25  	miss    uint32
    26  }
    27  
    28  func (p *BufferPool) poolNum(n int) int {
    29  	for i, x := range p.baseline {
    30  		if n <= x {
    31  			return i
    32  		}
    33  	}
    34  	return len(p.baseline)
    35  }
    36  
    37  // Get returns buffer with length of n.
    38  func (p *BufferPool) Get(n int) []byte {
    39  	if p == nil {
    40  		return make([]byte, n)
    41  	}
    42  	atomic.AddUint32(&p.get, 1)
    43  
    44  	poolNum := p.poolNum(n)
    45  
    46  	b := p.pool[poolNum].Get().(*[]byte)
    47  
    48  	if cap(*b) == 0 {
    49  		// If we grabbed nothing, increment the miss stats.
    50  		atomic.AddUint32(&p.miss, 1)
    51  
    52  		if poolNum == len(p.baseline) {
    53  			*b = make([]byte, n)
    54  			return *b
    55  		}
    56  
    57  		*b = make([]byte, p.baseline[poolNum])
    58  		*b = (*b)[:n]
    59  		return *b
    60  	} else {
    61  		// If there is enough capacity in the bytes grabbed, resize the length
    62  		// to n and return.
    63  		if n < cap(*b) {
    64  			atomic.AddUint32(&p.less, 1)
    65  			*b = (*b)[:n]
    66  			return *b
    67  		} else if n == cap(*b) {
    68  			atomic.AddUint32(&p.equal, 1)
    69  			*b = (*b)[:n]
    70  			return *b
    71  		} else if n > cap(*b) {
    72  			atomic.AddUint32(&p.greater, 1)
    73  		}
    74  	}
    75  
    76  	if poolNum == len(p.baseline) {
    77  		*b = make([]byte, n)
    78  		return *b
    79  	}
    80  	*b = make([]byte, p.baseline[poolNum])
    81  	*b = (*b)[:n]
    82  	return *b
    83  }
    84  
    85  // Put adds given buffer to the pool.
    86  func (p *BufferPool) Put(b []byte) {
    87  	if p == nil {
    88  		return
    89  	}
    90  
    91  	poolNum := p.poolNum(cap(b))
    92  
    93  	atomic.AddUint32(&p.put, 1)
    94  	p.pool[poolNum].Put(&b)
    95  }
    96  
    97  func (p *BufferPool) String() string {
    98  	if p == nil {
    99  		return "<nil>"
   100  	}
   101  	return fmt.Sprintf("BufferPool{B·%d G·%d P·%d <·%d =·%d >·%d M·%d}",
   102  		p.baseline, p.get, p.put, p.less, p.equal, p.greater, p.miss)
   103  }
   104  
   105  // NewBufferPool creates a new initialized 'buffer pool'.
   106  func NewBufferPool(baseline int) *BufferPool {
   107  	if baseline <= 0 {
   108  		panic("baseline can't be <= 0")
   109  	}
   110  	bufPool := &BufferPool{
   111  		baseline: [...]int{baseline / 4, baseline / 2, baseline, baseline * 2, baseline * 4},
   112  		pool: [6]sync.Pool{
   113  			{
   114  				New: func() interface{} { return new([]byte) },
   115  			},
   116  			{
   117  				New: func() interface{} { return new([]byte) },
   118  			},
   119  			{
   120  				New: func() interface{} { return new([]byte) },
   121  			},
   122  			{
   123  				New: func() interface{} { return new([]byte) },
   124  			},
   125  			{
   126  				New: func() interface{} { return new([]byte) },
   127  			},
   128  			{
   129  				New: func() interface{} { return new([]byte) },
   130  			},
   131  		},
   132  	}
   133  
   134  	return bufPool
   135  }
   136  

View as plain text