-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(blooms): Reduce jumps between buckets in blocks pool
- Loading branch information
1 parent
9af191f
commit df48414
Showing
4 changed files
with
178 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package pool | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"sync" | ||
) | ||
|
||
// NOTE this is pretty much a copy of prometheus pool | ||
|
||
// Pool is a bucketed pool for variably sized byte slices. | ||
type Pool struct { | ||
buckets []sync.Pool | ||
sizes []int | ||
// make is the function used to create an empty slice when none exist yet. | ||
make func(int) interface{} | ||
} | ||
|
||
// New returns a new Pool with size buckets for minSize to maxSize | ||
// increasing by the given factor. | ||
func New(minSize, maxSize int, factor float64, makeFunc func(int) interface{}) *Pool { | ||
if minSize < 1 { | ||
panic("invalid minimum pool size") | ||
} | ||
if maxSize < 1 { | ||
panic("invalid maximum pool size") | ||
} | ||
if factor < 2 { | ||
panic("invalid factor") | ||
} | ||
|
||
var sizes []int | ||
|
||
for s := minSize; s <= maxSize; s = int(float64(s) * factor) { | ||
sizes = append(sizes, s) | ||
} | ||
|
||
p := &Pool{ | ||
buckets: make([]sync.Pool, len(sizes)), | ||
sizes: sizes, | ||
make: makeFunc, | ||
} | ||
|
||
return p | ||
} | ||
|
||
func NewWithSizes(sizes []int, makeFunc func(int) interface{}) *Pool { | ||
if len(sizes) < 1 { | ||
panic("invalid pool sizes") | ||
} | ||
|
||
p := &Pool{ | ||
buckets: make([]sync.Pool, len(sizes)), | ||
sizes: sizes, | ||
make: makeFunc, | ||
} | ||
|
||
return p | ||
} | ||
|
||
// Get returns a new byte slices that fits the given size. | ||
func (p *Pool) Get(sz int) interface{} { | ||
for i, bktSize := range p.sizes { | ||
if sz > bktSize { | ||
continue | ||
} | ||
b := p.buckets[i].Get() | ||
if b == nil { | ||
b = p.make(bktSize) | ||
} | ||
return b | ||
} | ||
return p.make(sz) | ||
} | ||
|
||
// Put adds a slice to the right bucket in the pool. | ||
func (p *Pool) Put(s interface{}) { | ||
slice := reflect.ValueOf(s) | ||
|
||
if slice.Kind() != reflect.Slice { | ||
panic(fmt.Sprintf("%+v is not a slice", slice)) | ||
} | ||
for i, size := range p.sizes { | ||
if slice.Cap() > size { | ||
continue | ||
} | ||
p.buckets[i].Put(slice.Slice(0, 0).Interface()) | ||
return | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package pool | ||
|
||
import ( | ||
"github.com/stretchr/testify/require" | ||
"testing" | ||
) | ||
|
||
func TestPoolNew(t *testing.T) { | ||
testPool := New(1, 8, 2, func(size int) interface{} { | ||
return make([]int, size) | ||
}) | ||
cases := []struct { | ||
size int | ||
expectedCap int | ||
}{ | ||
{ | ||
size: -1, | ||
expectedCap: 1, | ||
}, | ||
{ | ||
size: 3, | ||
expectedCap: 4, | ||
}, | ||
{ | ||
size: 10, | ||
expectedCap: 10, | ||
}, | ||
} | ||
for _, c := range cases { | ||
ret := testPool.Get(c.size) | ||
require.Equal(t, c.expectedCap, cap(ret.([]int))) | ||
testPool.Put(ret) | ||
} | ||
} | ||
|
||
func TestPoolNewWithSizes(t *testing.T) { | ||
testPool := NewWithSizes([]int{1, 2, 4, 8}, func(size int) interface{} { | ||
return make([]int, size) | ||
}) | ||
cases := []struct { | ||
size int | ||
expectedCap int | ||
}{ | ||
{ | ||
size: -1, | ||
expectedCap: 1, | ||
}, | ||
{ | ||
size: 3, | ||
expectedCap: 4, | ||
}, | ||
{ | ||
size: 10, | ||
expectedCap: 10, | ||
}, | ||
} | ||
for _, c := range cases { | ||
ret := testPool.Get(c.size) | ||
require.Equal(t, c.expectedCap, cap(ret.([]int))) | ||
testPool.Put(ret) | ||
} | ||
} |