5748: Fix leaks in GetBlock error handling and PutBlock use of GetBlock where
[arvados.git] / services / keepstore / bufferpool.go
1 package main
2
3 import (
4         "log"
5         "sync"
6         "time"
7 )
8
9 type bufferPool struct {
10         // limiter has a "true" placeholder for each in-use buffer.
11         limiter chan bool
12         // Pool has unused buffers.
13         sync.Pool
14 }
15
16 func newBufferPool(count int, bufSize int) *bufferPool {
17         p := bufferPool{}
18         p.New = func() interface{} {
19                 return make([]byte, bufSize)
20         }
21         p.limiter = make(chan bool, count)
22         return &p
23 }
24
25 func (p *bufferPool) Get(size int) []byte {
26         select {
27         case p.limiter <- true:
28         default:
29                 t0 := time.Now()
30                 log.Printf("reached max buffers (%d), waiting", cap(p.limiter))
31                 p.limiter <- true
32                 log.Printf("waited %v for a buffer", time.Since(t0))
33         }
34         buf := p.Pool.Get().([]byte)
35         if cap(buf) < size {
36                 log.Fatalf("bufferPool Get(size=%d) but max=%d", size, cap(buf))
37         }
38         return buf[:size]
39 }
40
41 func (p *bufferPool) Put(buf []byte) {
42         if buf != nil {
43                 p.Pool.Put(buf)
44                 <-p.limiter
45         }
46 }