github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/cache/alloc.go (about) 1 // Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package cache 6 7 const ( 8 // The min size of a byte slice held in an allocCache instance. Byte slices 9 // smaller than this value will not be cached. 10 allocCacheMinSize = 1024 11 // The max size of a byte slice held in an allocCache instance. Byte slices 12 // larger than this value will not be cached. 13 allocCacheMaxSize = 64 * 1024 14 allocCacheCountLimit = 16 15 // The maximum size of data held in a single allocCache instance. There will 16 // be O(num-cpus) allocCaches per Cache. 17 allocCacheSizeLimit = 512 * 1024 18 ) 19 20 // allocCache implements a small cache for the byte slice allocations used by 21 // the Cache. If an allocCache is empty, allocations are passed through to the 22 // Go runtime allocator. An allocCache holds a list of recently freed buffers 23 // that is capped at 16 entries and 512KB in size. When a buffer is freed, the 24 // existing cached buffers are trimmed until the new entry can fit with the 25 // count and size limits. When a buffer is allocated, this cached list is 26 // walked from beginning to end looking for the first buffer which is the same 27 // size class as the allocation. Size classes are multiples of 1024. 28 type allocCache struct { 29 size int 30 bufs [][]byte 31 } 32 33 func sizeToClass(size int) int { 34 return (size - 1) / 1024 35 } 36 37 func classToSize(class int) int { 38 return (class + 1) * 1024 39 } 40 41 func (c *allocCache) alloc(n int) []byte { 42 if n < allocCacheMinSize || n >= allocCacheMaxSize { 43 return make([]byte, n) 44 } 45 46 class := sizeToClass(n) 47 for i := range c.bufs { 48 if t := c.bufs[i]; sizeToClass(len(t)) == class { 49 j := len(c.bufs) - 1 50 c.bufs[i], c.bufs[j] = c.bufs[j], c.bufs[i] 51 c.bufs[j] = nil 52 c.bufs = c.bufs[:j] 53 c.size -= len(t) 54 return t[:n] 55 } 56 } 57 58 return make([]byte, n, classToSize(class)) 59 } 60 61 func (c *allocCache) free(b []byte) { 62 n := cap(b) 63 if n < allocCacheMinSize || n >= allocCacheMaxSize { 64 return 65 } 66 b = b[:n:n] 67 68 for c.size+n >= allocCacheSizeLimit || len(c.bufs) >= allocCacheCountLimit { 69 i := len(c.bufs) - 1 70 t := c.bufs[i] 71 c.size -= len(t) 72 c.bufs[i] = nil 73 c.bufs = c.bufs[:i] 74 } 75 c.bufs = append(c.bufs, b) 76 c.size += n 77 }