kubo/blocks/blockstore/bloom_cache_test.go
Jakub Sztandera e92e6662a7 test: fix races in bloomcache tests
License: MIT
Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
2016-07-04 20:34:07 +02:00

147 lines
3.0 KiB
Go

package blockstore
import (
"fmt"
"sync"
"testing"
"time"
"github.com/ipfs/go-ipfs/blocks"
ds "gx/ipfs/QmfQzVugPq1w5shWRcLWSeiHF4a2meBX7yVD8Vw7GWJM9o/go-datastore"
dsq "gx/ipfs/QmfQzVugPq1w5shWRcLWSeiHF4a2meBX7yVD8Vw7GWJM9o/go-datastore/query"
syncds "gx/ipfs/QmfQzVugPq1w5shWRcLWSeiHF4a2meBX7yVD8Vw7GWJM9o/go-datastore/sync"
)
func TestReturnsErrorWhenSizeNegative(t *testing.T) {
bs := NewBlockstore(syncds.MutexWrap(ds.NewMapDatastore()))
_, err := BloomCached(bs, 100, -1)
if err == nil {
t.Fail()
}
_, err = BloomCached(bs, -1, 100)
if err == nil {
t.Fail()
}
}
func TestRemoveCacheEntryOnDelete(t *testing.T) {
b := blocks.NewBlock([]byte("foo"))
cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
bs := NewBlockstore(syncds.MutexWrap(cd))
cachedbs, err := BloomCached(bs, 1, 1)
if err != nil {
t.Fatal(err)
}
cachedbs.Put(b)
cd.Lock()
writeHitTheDatastore := false
cd.Unlock()
cd.SetFunc(func() {
writeHitTheDatastore = true
})
cachedbs.DeleteBlock(b.Key())
cachedbs.Put(b)
if !writeHitTheDatastore {
t.Fail()
}
}
func TestElideDuplicateWrite(t *testing.T) {
cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
bs := NewBlockstore(syncds.MutexWrap(cd))
cachedbs, err := BloomCached(bs, 1, 1)
if err != nil {
t.Fatal(err)
}
b1 := blocks.NewBlock([]byte("foo"))
cachedbs.Put(b1)
cd.SetFunc(func() {
t.Fatal("write hit the datastore")
})
cachedbs.Put(b1)
}
func TestHasIsBloomCached(t *testing.T) {
cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
bs := NewBlockstore(syncds.MutexWrap(cd))
for i := 0; i < 1000; i++ {
bs.Put(blocks.NewBlock([]byte(fmt.Sprintf("data: %d", i))))
}
cachedbs, err := BloomCached(bs, 256*1024, 128)
if err != nil {
t.Fatal(err)
}
select {
case <-cachedbs.rebuildChan:
case <-time.After(1 * time.Second):
t.Fatalf("Timeout wating for rebuild: %d", cachedbs.bloom.ElementsAdded())
}
cacheFails := 0
cd.SetFunc(func() {
cacheFails++
})
for i := 0; i < 1000; i++ {
cachedbs.Has(blocks.NewBlock([]byte(fmt.Sprintf("data: %d", i+2000))).Key())
}
if float64(cacheFails)/float64(1000) > float64(0.05) {
t.Fatal("Bloom filter has cache miss rate of more than 5%")
}
}
type callbackDatastore struct {
sync.Mutex
f func()
ds ds.Datastore
}
func (c *callbackDatastore) SetFunc(f func()) {
c.Lock()
defer c.Unlock()
c.f = f
}
func (c *callbackDatastore) CallF() {
c.Lock()
defer c.Unlock()
c.f()
}
func (c *callbackDatastore) Put(key ds.Key, value interface{}) (err error) {
c.CallF()
return c.ds.Put(key, value)
}
func (c *callbackDatastore) Get(key ds.Key) (value interface{}, err error) {
c.CallF()
return c.ds.Get(key)
}
func (c *callbackDatastore) Has(key ds.Key) (exists bool, err error) {
c.CallF()
return c.ds.Has(key)
}
func (c *callbackDatastore) Delete(key ds.Key) (err error) {
c.CallF()
return c.ds.Delete(key)
}
func (c *callbackDatastore) Query(q dsq.Query) (dsq.Results, error) {
c.CallF()
return c.ds.Query(q)
}
func (c *callbackDatastore) Batch() (ds.Batch, error) {
return ds.NewBasicBatch(c), nil
}