diff --git a/storage/local/persistence.go b/storage/local/persistence.go index 08a78e427..67de524bc 100644 --- a/storage/local/persistence.go +++ b/storage/local/persistence.go @@ -71,11 +71,7 @@ const ( indexingQueueCapacity = 1024 * 16 ) -var ( - fpLen = len(clientmodel.Fingerprint(0).String()) // Length of a fingerprint as string. - - byteBufPool = sync.Pool{New: func() interface{} { return make([]byte, 0, 3*chunkLenWithHeader) }} -) +var fpLen = len(clientmodel.Fingerprint(0).String()) // Length of a fingerprint as string. const ( flagHeadChunkPersisted byte = 1 << iota @@ -128,6 +124,8 @@ type persistence struct { fLock flock.Releaser // The file lock to protect against concurrent usage. shouldSync syncStrategy + + bufPool sync.Pool } // newPersistence returns a newly allocated persistence backed by local disk storage, ready to use. @@ -239,6 +237,10 @@ func newPersistence(basePath string, dirty, pedanticChecks bool, shouldSync sync dirtyFileName: dirtyPath, fLock: fLock, shouldSync: shouldSync, + // Create buffers of length 3*chunkLenWithHeader by default because that is still reasonably small + // and at the same time enough for many uses. The contract is to never return buffer smaller than + // that to the pool so that callers can rely on a minimum buffer size. + bufPool: sync.Pool{New: func() interface{} { return make([]byte, 0, 3*chunkLenWithHeader) }}, } if p.dirty { @@ -383,9 +385,9 @@ func (p *persistence) loadChunks(fp clientmodel.Fingerprint, indexes []int, inde defer f.Close() chunks := make([]chunk, 0, len(indexes)) - buf := byteBufPool.Get().([]byte) + buf := p.bufPool.Get().([]byte) defer func() { - byteBufPool.Put(buf) + p.bufPool.Put(buf) }() for i := 0; i < len(indexes); i++ { diff --git a/storage/local/persistence_test.go b/storage/local/persistence_test.go index d6b75d2ee..fc21b8d24 100644 --- a/storage/local/persistence_test.go +++ b/storage/local/persistence_test.go @@ -15,6 +15,7 @@ package local import ( "reflect" + "sync" "testing" clientmodel "github.com/prometheus/client_golang/model" @@ -894,6 +895,7 @@ var fpStrings = []string{ func BenchmarkLoadChunksSequentially(b *testing.B) { p := persistence{ basePath: "fixtures", + bufPool: sync.Pool{New: func() interface{} { return make([]byte, 0, 3*chunkLenWithHeader) }}, } sequentialIndexes := make([]int, 47) for i := range sequentialIndexes { @@ -918,6 +920,7 @@ func BenchmarkLoadChunksSequentially(b *testing.B) { func BenchmarkLoadChunksRandomly(b *testing.B) { p := persistence{ basePath: "fixtures", + bufPool: sync.Pool{New: func() interface{} { return make([]byte, 0, 3*chunkLenWithHeader) }}, } randomIndexes := []int{1, 5, 6, 8, 11, 14, 18, 23, 29, 33, 42, 46}