* Fix bufferpool puts (ref #4976) There was a logic error in Put() which made us put all large blocks into segment zero, where we subsequently did not look for them. I also added a lowest threshold, as we otherwise allocate a 128KiB buffer when we need 24 bytes for a header and such. * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * smaller stress * cap/len * wip * wip
This commit is contained in:
committed by
Audrius Butkevicius
parent
98a1adebe1
commit
6755a9ca63
132
lib/protocol/bufferpool_test.go
Normal file
132
lib/protocol/bufferpool_test.go
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright (C) 2019 The Protocol Authors.
|
||||
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
)
|
||||
|
||||
func TestGetBucketNumbers(t *testing.T) {
|
||||
cases := []struct {
|
||||
size int
|
||||
bkt int
|
||||
panics bool
|
||||
}{
|
||||
{size: 1024, bkt: 0},
|
||||
{size: MinBlockSize, bkt: 0},
|
||||
{size: MinBlockSize + 1, bkt: 1},
|
||||
{size: 2*MinBlockSize - 1, bkt: 1},
|
||||
{size: 2 * MinBlockSize, bkt: 1},
|
||||
{size: 2*MinBlockSize + 1, bkt: 2},
|
||||
{size: MaxBlockSize, bkt: len(BlockSizes) - 1},
|
||||
{size: MaxBlockSize + 1, panics: true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
if tc.panics {
|
||||
shouldPanic(t, func() { getBucketForLen(tc.size) })
|
||||
} else {
|
||||
res := getBucketForLen(tc.size)
|
||||
if res != tc.bkt {
|
||||
t.Errorf("block of size %d should get from bucket %d, not %d", tc.size, tc.bkt, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPutBucketNumbers(t *testing.T) {
|
||||
cases := []struct {
|
||||
size int
|
||||
bkt int
|
||||
panics bool
|
||||
}{
|
||||
{size: 1024, panics: true},
|
||||
{size: MinBlockSize, bkt: 0},
|
||||
{size: MinBlockSize + 1, panics: true},
|
||||
{size: 2 * MinBlockSize, bkt: 1},
|
||||
{size: MaxBlockSize, bkt: len(BlockSizes) - 1},
|
||||
{size: MaxBlockSize + 1, panics: true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
if tc.panics {
|
||||
shouldPanic(t, func() { putBucketForCap(tc.size) })
|
||||
} else {
|
||||
res := putBucketForCap(tc.size)
|
||||
if res != tc.bkt {
|
||||
t.Errorf("block of size %d should put into bucket %d, not %d", tc.size, tc.bkt, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStressBufferPool(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
const routines = 10
|
||||
const runtime = 2 * time.Second
|
||||
|
||||
bp := newBufferPool()
|
||||
t0 := time.Now()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
fail := make(chan struct{}, routines)
|
||||
for i := 0; i < routines; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for time.Since(t0) < runtime {
|
||||
blocks := make([][]byte, 10)
|
||||
for i := range blocks {
|
||||
// Request a block of random size with the range
|
||||
// covering smaller-than-min to larger-than-max and
|
||||
// everything in between.
|
||||
want := rand.Intn(1.5 * MaxBlockSize)
|
||||
blocks[i] = bp.Get(want)
|
||||
if len(blocks[i]) != want {
|
||||
fail <- struct{}{}
|
||||
return
|
||||
}
|
||||
}
|
||||
for i := range blocks {
|
||||
bp.Put(blocks[i])
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
select {
|
||||
case <-fail:
|
||||
t.Fatal("a block was bad size")
|
||||
default:
|
||||
}
|
||||
|
||||
t.Log(bp.puts, bp.skips, bp.misses, bp.hits)
|
||||
if bp.puts == 0 || bp.skips == 0 || bp.misses == 0 {
|
||||
t.Error("didn't exercise some paths")
|
||||
}
|
||||
var hits int64
|
||||
for _, h := range bp.hits {
|
||||
hits += h
|
||||
}
|
||||
if hits == 0 {
|
||||
t.Error("didn't exercise some paths")
|
||||
}
|
||||
}
|
||||
|
||||
func shouldPanic(t *testing.T, fn func()) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("did not panic")
|
||||
}
|
||||
}()
|
||||
|
||||
fn()
|
||||
}
|
||||
Reference in New Issue
Block a user