mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
common/bloom: improve filter, fix bugs
This commit is contained in:
parent
5cf988443f
commit
27a143810d
2 changed files with 90 additions and 38 deletions
|
|
@ -8,72 +8,77 @@ import (
|
||||||
bloomfilter "github.com/holiman/bloomfilter/v2"
|
bloomfilter "github.com/holiman/bloomfilter/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
k = 4
|
||||||
|
)
|
||||||
|
|
||||||
type ExpiringBloom struct {
|
type ExpiringBloom struct {
|
||||||
currentBloom int
|
currentBloom int
|
||||||
union *bloomfilter.Filter
|
union *bloomfilter.Filter
|
||||||
blooms []*bloomfilter.Filter
|
blooms []*bloomfilter.Filter
|
||||||
filterM uint64
|
size uint64
|
||||||
filterK uint64
|
|
||||||
|
|
||||||
timer *time.Ticker
|
timer *time.Ticker
|
||||||
mu sync.RWMutex // Mutex only locks the currentBloom variable
|
// Mutex lock the currentBloom and union variables
|
||||||
|
mu sync.RWMutex
|
||||||
closeCh chan struct{}
|
closeCh chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExpiringBloom(n, m, k uint64, timeout time.Duration) *ExpiringBloom {
|
func NewExpiringBloom(n, m uint64, timeout time.Duration) (*ExpiringBloom, error) {
|
||||||
|
union, err := bloomfilter.New(m*8, k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
blooms := make([]*bloomfilter.Filter, 0, n)
|
blooms := make([]*bloomfilter.Filter, 0, n)
|
||||||
for i := 0; i < int(n); i++ {
|
for i := 0; i < int(n); i++ {
|
||||||
filter, err := bloomfilter.New(m, k)
|
filter, err := union.NewCompatible()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
blooms = append(blooms, filter)
|
blooms = append(blooms, filter)
|
||||||
}
|
}
|
||||||
union, err := bloomfilter.New(m, k)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
filter := ExpiringBloom{
|
filter := ExpiringBloom{
|
||||||
currentBloom: 0,
|
currentBloom: 0,
|
||||||
blooms: blooms,
|
blooms: blooms,
|
||||||
union: union,
|
union: union,
|
||||||
filterM: m,
|
size: m * 8,
|
||||||
filterK: k,
|
|
||||||
timer: time.NewTicker(timeout),
|
timer: time.NewTicker(timeout),
|
||||||
closeCh: make(chan struct{}),
|
closeCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
go filter.loop()
|
go filter.loop()
|
||||||
return &filter
|
|
||||||
|
return &filter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ExpiringBloom) loop() {
|
func (e *ExpiringBloom) loop() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-e.timer.C:
|
case <-e.timer.C:
|
||||||
// Reset the filters on every tick
|
e.tick()
|
||||||
e.mu.Lock()
|
case <-e.closeCh:
|
||||||
var err error
|
return
|
||||||
e.blooms[e.currentBloom], err = bloomfilter.New(e.filterM, e.filterK)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ExpiringBloom) tick() {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
|
// Advance the current bloom
|
||||||
e.currentBloom++
|
e.currentBloom++
|
||||||
if e.currentBloom == len(e.blooms)-1 {
|
if e.currentBloom == len(e.blooms) {
|
||||||
e.currentBloom = 0
|
e.currentBloom = 0
|
||||||
}
|
}
|
||||||
|
// Clear the filter
|
||||||
|
e.blooms[e.currentBloom], _ = e.blooms[e.currentBloom].NewCompatible()
|
||||||
// Recreate the union filter
|
// Recreate the union filter
|
||||||
e.union, err = bloomfilter.New(e.filterM, e.filterK)
|
e.union, _ = e.union.NewCompatible()
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
for _, bloom := range e.blooms {
|
for _, bloom := range e.blooms {
|
||||||
e.union.UnionInPlace(bloom)
|
e.union.UnionInPlace(bloom)
|
||||||
}
|
}
|
||||||
e.mu.Unlock()
|
|
||||||
case <-e.closeCh:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ExpiringBloom) Stop() {
|
func (e *ExpiringBloom) Stop() {
|
||||||
|
|
|
||||||
|
|
@ -36,19 +36,66 @@ func (h hashable) Size() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBloom(t *testing.T) {
|
func TestBloom(t *testing.T) {
|
||||||
bloom := NewExpiringBloom(2, 10, 10, 10*time.Millisecond)
|
bloom, _ := NewExpiringBloom(3, 1024, 10*time.Millisecond)
|
||||||
|
|
||||||
testKey := hashable{[]byte{0x01}}
|
testKey := hashable{[]byte{0x01}}
|
||||||
bloom.Put(testKey)
|
bloom.Put(testKey)
|
||||||
if !bloom.Contain(testKey) {
|
if !bloom.Contain(testKey) {
|
||||||
t.Fatal()
|
t.Fatal()
|
||||||
}
|
}
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(11 * time.Millisecond)
|
||||||
if !bloom.Contain(testKey) {
|
if !bloom.Contain(testKey) {
|
||||||
t.Fatal()
|
t.Fatal()
|
||||||
}
|
}
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(11 * time.Millisecond)
|
||||||
|
if !bloom.Contain(testKey) {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
time.Sleep(11 * time.Millisecond)
|
||||||
if bloom.Contain(testKey) {
|
if bloom.Contain(testKey) {
|
||||||
t.Fatal()
|
t.Fatal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBloom2(t *testing.T) {
|
||||||
|
bloom, _ := NewExpiringBloom(3, 1024, 10*time.Second)
|
||||||
|
|
||||||
|
testKey := hashable{[]byte{0x01}}
|
||||||
|
// Put key in bloom 0
|
||||||
|
bloom.Put(testKey)
|
||||||
|
if !bloom.Contain(testKey) {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
// Override bloom 1
|
||||||
|
bloom.tick()
|
||||||
|
if !bloom.Contain(testKey) {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
// Override bloom 2
|
||||||
|
bloom.tick()
|
||||||
|
if !bloom.Contain(testKey) {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
// Override bloom 0
|
||||||
|
bloom.tick()
|
||||||
|
if bloom.Contain(testKey) {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPut(b *testing.B) {
|
||||||
|
bloom, _ := NewExpiringBloom(2, 1024, 10*time.Second)
|
||||||
|
|
||||||
|
testKey := hashable{[]byte{0x01}}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bloom.Put(testKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkTick(b *testing.B) {
|
||||||
|
bloom, _ := NewExpiringBloom(2, 1024, 10*time.Second)
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bloom.tick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue