Skip to content
This repository was archived by the owner on Jun 19, 2023. It is now read-only.

Commit c922e24

Browse files
authored
Merge pull request #9 from ipfs/fix/6
fix test race condition
2 parents d9bc264 + 5e44d7b commit c922e24

File tree

2 files changed

+56
-46
lines changed

2 files changed

+56
-46
lines changed

bloom_cache.go

+51-37
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package blockstore
22

33
import (
44
"context"
5+
"fmt"
56
"sync/atomic"
67
"time"
78

@@ -19,82 +20,95 @@ func bloomCached(ctx context.Context, bs Blockstore, bloomSize, hashCount int) (
1920
if err != nil {
2021
return nil, err
2122
}
22-
bc := &bloomcache{blockstore: bs, bloom: bl}
23-
bc.hits = metrics.NewCtx(ctx, "bloom.hits_total",
24-
"Number of cache hits in bloom cache").Counter()
25-
bc.total = metrics.NewCtx(ctx, "bloom_total",
26-
"Total number of requests to bloom cache").Counter()
27-
28-
bc.Invalidate()
29-
go bc.Rebuild(ctx)
30-
if metrics.Active() {
31-
go func() {
23+
bc := &bloomcache{
24+
blockstore: bs,
25+
bloom: bl,
26+
hits: metrics.NewCtx(ctx, "bloom.hits_total",
27+
"Number of cache hits in bloom cache").Counter(),
28+
total: metrics.NewCtx(ctx, "bloom_total",
29+
"Total number of requests to bloom cache").Counter(),
30+
buildChan: make(chan struct{}),
31+
}
32+
go func() {
33+
err := bc.build(ctx)
34+
if err != nil {
35+
select {
36+
case <-ctx.Done():
37+
log.Warning("Cache rebuild closed by context finishing: ", err)
38+
default:
39+
log.Error(err)
40+
}
41+
return
42+
}
43+
if metrics.Active() {
3244
fill := metrics.NewCtx(ctx, "bloom_fill_ratio",
3345
"Ratio of bloom filter fullnes, (updated once a minute)").Gauge()
3446

35-
<-bc.rebuildChan
3647
t := time.NewTicker(1 * time.Minute)
48+
defer t.Stop()
3749
for {
3850
select {
3951
case <-ctx.Done():
40-
t.Stop()
4152
return
4253
case <-t.C:
4354
fill.Set(bc.bloom.FillRatio())
4455
}
4556
}
46-
}()
47-
}
57+
}
58+
}()
4859
return bc, nil
4960
}
5061

5162
type bloomcache struct {
52-
bloom *bloom.Bloom
5363
active int32
5464

55-
// This chan is only used for testing to wait for bloom to enable
56-
rebuildChan chan struct{}
57-
blockstore Blockstore
65+
bloom *bloom.Bloom
66+
buildErr error
67+
68+
buildChan chan struct{}
69+
blockstore Blockstore
5870

5971
// Statistics
6072
hits metrics.Counter
6173
total metrics.Counter
6274
}
6375

64-
func (b *bloomcache) Invalidate() {
65-
b.rebuildChan = make(chan struct{})
66-
atomic.StoreInt32(&b.active, 0)
67-
}
68-
6976
func (b *bloomcache) BloomActive() bool {
7077
return atomic.LoadInt32(&b.active) != 0
7178
}
7279

73-
func (b *bloomcache) Rebuild(ctx context.Context) {
74-
evt := log.EventBegin(ctx, "bloomcache.Rebuild")
80+
func (b *bloomcache) Wait(ctx context.Context) error {
81+
select {
82+
case <-ctx.Done():
83+
return ctx.Err()
84+
case <-b.buildChan:
85+
return b.buildErr
86+
}
87+
}
88+
89+
func (b *bloomcache) build(ctx context.Context) error {
90+
evt := log.EventBegin(ctx, "bloomcache.build")
7591
defer evt.Done()
92+
defer close(b.buildChan)
7693

7794
ch, err := b.blockstore.AllKeysChan(ctx)
7895
if err != nil {
79-
log.Errorf("AllKeysChan failed in bloomcache rebuild with: %v", err)
80-
return
96+
b.buildErr = fmt.Errorf("AllKeysChan failed in bloomcache rebuild with: %v", err)
97+
return b.buildErr
8198
}
82-
finish := false
83-
for !finish {
99+
for {
84100
select {
85101
case key, ok := <-ch:
86-
if ok {
87-
b.bloom.AddTS(key.Bytes()) // Use binary key, the more compact the better
88-
} else {
89-
finish = true
102+
if !ok {
103+
atomic.StoreInt32(&b.active, 1)
104+
return nil
90105
}
106+
b.bloom.AddTS(key.Bytes()) // Use binary key, the more compact the better
91107
case <-ctx.Done():
92-
log.Warning("Cache rebuild closed by context finishing.")
93-
return
108+
b.buildErr = ctx.Err()
109+
return b.buildErr
94110
}
95111
}
96-
close(b.rebuildChan)
97-
atomic.StoreInt32(&b.active, 1)
98112
}
99113

100114
func (b *bloomcache) DeleteBlock(k cid.Cid) error {

bloom_cache_test.go

+5-9
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,8 @@ func TestPutManyAddsToBloom(t *testing.T) {
3737
t.Fatal(err)
3838
}
3939

40-
select {
41-
case <-cachedbs.rebuildChan:
42-
case <-ctx.Done():
43-
t.Fatalf("Timeout wating for rebuild: %d", cachedbs.bloom.ElementsAdded())
40+
if err := cachedbs.Wait(ctx); err != nil {
41+
t.Fatalf("Failed while waiting for the filter to build: %d", cachedbs.bloom.ElementsAdded())
4442
}
4543

4644
block1 := blocks.NewBlock([]byte("foo"))
@@ -107,10 +105,8 @@ func TestHasIsBloomCached(t *testing.T) {
107105
t.Fatal(err)
108106
}
109107

110-
select {
111-
case <-cachedbs.rebuildChan:
112-
case <-ctx.Done():
113-
t.Fatalf("Timeout wating for rebuild: %d", cachedbs.bloom.ElementsAdded())
108+
if err := cachedbs.Wait(ctx); err != nil {
109+
t.Fatalf("Failed while waiting for the filter to build: %d", cachedbs.bloom.ElementsAdded())
114110
}
115111

116112
cacheFails := 0
@@ -123,7 +119,7 @@ func TestHasIsBloomCached(t *testing.T) {
123119
}
124120

125121
if float64(cacheFails)/float64(1000) > float64(0.05) {
126-
t.Fatal("Bloom filter has cache miss rate of more than 5%")
122+
t.Fatalf("Bloom filter has cache miss rate of more than 5%%")
127123
}
128124

129125
cacheFails = 0

0 commit comments

Comments
 (0)