mirror of
https://github.com/luscis/openlan.git
synced 2025-10-07 09:30:54 +08:00
93 lines
1.6 KiB
Go
93 lines
1.6 KiB
Go
package internal
|
|
|
|
import (
|
|
"hash/fnv"
|
|
"sync"
|
|
|
|
"github.com/riobard/go-bloom"
|
|
)
|
|
|
|
// simply use Double FNV here as our Bloom Filter hash
|
|
func doubleFNV(b []byte) (uint64, uint64) {
|
|
hx := fnv.New64()
|
|
hx.Write(b)
|
|
x := hx.Sum64()
|
|
hy := fnv.New64a()
|
|
hy.Write(b)
|
|
y := hy.Sum64()
|
|
return x, y
|
|
}
|
|
|
|
type BloomRing struct {
|
|
slotCapacity int
|
|
slotPosition int
|
|
slotCount int
|
|
entryCounter int
|
|
slots []bloom.Filter
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
func NewBloomRing(slot, capacity int, falsePositiveRate float64) *BloomRing {
|
|
// Calculate entries for each slot
|
|
r := &BloomRing{
|
|
slotCapacity: capacity / slot,
|
|
slotCount: slot,
|
|
slots: make([]bloom.Filter, slot),
|
|
}
|
|
for i := 0; i < slot; i++ {
|
|
r.slots[i] = bloom.New(r.slotCapacity, falsePositiveRate, doubleFNV)
|
|
}
|
|
return r
|
|
}
|
|
|
|
func (r *BloomRing) Add(b []byte) {
|
|
if r == nil {
|
|
return
|
|
}
|
|
r.mutex.Lock()
|
|
defer r.mutex.Unlock()
|
|
r.add(b)
|
|
}
|
|
|
|
func (r *BloomRing) add(b []byte) {
|
|
slot := r.slots[r.slotPosition]
|
|
if r.entryCounter > r.slotCapacity {
|
|
// Move to next slot and reset
|
|
r.slotPosition = (r.slotPosition + 1) % r.slotCount
|
|
slot = r.slots[r.slotPosition]
|
|
slot.Reset()
|
|
r.entryCounter = 0
|
|
}
|
|
r.entryCounter++
|
|
slot.Add(b)
|
|
}
|
|
|
|
func (r *BloomRing) Test(b []byte) bool {
|
|
if r == nil {
|
|
return false
|
|
}
|
|
r.mutex.RLock()
|
|
defer r.mutex.RUnlock()
|
|
test := r.test(b)
|
|
return test
|
|
}
|
|
|
|
func (r *BloomRing) test(b []byte) bool {
|
|
for _, s := range r.slots {
|
|
if s.Test(b) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (r *BloomRing) Check(b []byte) bool {
|
|
r.mutex.Lock()
|
|
defer r.mutex.Unlock()
|
|
if r.Test(b) {
|
|
return true
|
|
}
|
|
r.Add(b)
|
|
return false
|
|
}
|