Skip to content

Commit

Permalink
Decouple SyncFilter from ordinary Filter
Browse files Browse the repository at this point in the history
Programs that use the SyncFilter no longer get the Filter code linked
in. Shaves ~1.5KiB off the Syncthing binary.
  • Loading branch information
greatroar committed Sep 26, 2022
1 parent 6523705 commit c8cf324
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 22 deletions.
34 changes: 20 additions & 14 deletions bloomfilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ type Filter struct {
// single hash passed in by the client. It is silently increased to two if
// a lower value is given.
func New(nbits uint64, nhashes int) *Filter {
nbits, nhashes = fixBitsAndHashes(nbits, nhashes)

return &Filter{
b: make([]block, nbits/BlockBits),
k: nhashes,
}
}

func fixBitsAndHashes(nbits uint64, nhashes int) (uint64, int) {
if nbits < 1 {
nbits = BlockBits
}
Expand All @@ -79,16 +88,13 @@ func New(nbits uint64, nhashes int) *Filter {
nbits += BlockBits - nbits%BlockBits
}

return &Filter{
b: make([]block, nbits/BlockBits),
k: nhashes,
}
return nbits, nhashes
}

// Add insert a key with hash value h into f.
func (f *Filter) Add(h uint64) {
h1, h2 := uint32(h>>32), uint32(h)
b := f.getblock(h2)
b := getblock(f.b, h2)

for i := 1; i < f.k; i++ {
h1, h2 = doublehash(h1, h2, i)
Expand All @@ -112,11 +118,11 @@ const log1minus1divBlockbits = -0.0019550348358033505576274922418668121377
// and Nejdl, summed over the blocks
// (https://www.win.tue.nl/~opapapetrou/papers/Bloomfilters-DAPD.pdf).
func (f *Filter) Cardinality() float64 {
return f.cardinality(onescount)
return cardinality(f.k, f.b, onescount)
}

func (f *Filter) cardinality(onescount func(*block) int) float64 {
k := float64(f.k) - 1
func cardinality(nhashes int, b []block, onescount func(*block) int) float64 {
k := float64(nhashes - 1)

// The probability of some bit not being set in a single insertion is
// p0 = (1-1/BlockBits)^k.
Expand All @@ -125,8 +131,8 @@ func (f *Filter) cardinality(onescount func(*block) int) float64 {
logProb0Inv := 1 / (k * log1minus1divBlockbits)

var n float64
for i := range f.b {
ones := onescount(&f.b[i])
for i := range b {
ones := onescount(&b[i])
if ones == 0 {
continue
}
Expand Down Expand Up @@ -166,7 +172,7 @@ func (f *Filter) Fill() {
// It may return a false positive.
func (f *Filter) Has(h uint64) bool {
h1, h2 := uint32(h>>32), uint32(h)
b := f.getblock(h2)
b := getblock(f.b, h2)

for i := 1; i < f.k; i++ {
h1, h2 = doublehash(h1, h2, i)
Expand Down Expand Up @@ -234,9 +240,9 @@ const (
// A block is a fixed-size Bloom filter, used as a shard of a Filter.
type block [blockWords]uint32

func (f *Filter) getblock(h2 uint32) *block {
i := reducerange(h2, uint32(len(f.b)))
return &f.b[i]
func getblock(b []block, h2 uint32) *block {
i := reducerange(h2, uint32(len(b)))
return &b[i]
}

// reducerange maps i to an integer in the range [0,n).
Expand Down
22 changes: 14 additions & 8 deletions sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,23 @@ type SyncFilter struct {
// single hash passed in by the client. It is silently increased to two if
// a lower value is given.
func NewSync(nbits uint64, nhashes int) *SyncFilter {
return (*SyncFilter)(New(nbits, nhashes))
nbits, nhashes = fixBitsAndHashes(nbits, nhashes)

return &SyncFilter{
b: make([]block, nbits/BlockBits),
k: nhashes,
}

}

// Add insert a key with hash value h into f.
func (f *SyncFilter) Add(h uint64) {
h1, h2 := uint32(h>>32), uint32(h)
b := (*Filter)(f).getblock(h2)
b := getblock(f.b, h2)

for i := 1; i < f.k; i++ {
h1, h2 = doublehash(h1, h2, i)
b.setbitAtomic(h1)
setbitAtomic(b, h1)
}
}

Expand All @@ -72,7 +78,7 @@ func (f *SyncFilter) Add(h uint64) {
// before the concurrent updates started and what is returned
// after the updates complete.
func (f *SyncFilter) Cardinality() float64 {
return (*Filter)(f).cardinality(onescountAtomic)
return cardinality(f.k, f.b, onescountAtomic)
}

// Empty reports whether f contains no keys.
Expand Down Expand Up @@ -104,26 +110,26 @@ func (f *SyncFilter) Fill() {
// It may return a false positive.
func (f *SyncFilter) Has(h uint64) bool {
h1, h2 := uint32(h>>32), uint32(h)
b := (*Filter)(f).getblock(h2)
b := getblock(f.b, h2)

for i := 1; i < f.k; i++ {
h1, h2 = doublehash(h1, h2, i)
if !b.getbitAtomic(h1) {
if !getbitAtomic(b, h1) {
return false
}
}
return true
}

// getbitAtomic reports whether bit (i modulo BlockBits) is set.
func (b *block) getbitAtomic(i uint32) bool {
func getbitAtomic(b *block, i uint32) bool {
bit := uint32(1) << (i % wordSize)
x := atomic.LoadUint32(&(*b)[(i/wordSize)%blockWords])
return x&bit != 0
}

// setbit sets bit (i modulo BlockBits) of b, atomically.
func (b *block) setbitAtomic(i uint32) {
func setbitAtomic(b *block, i uint32) {
bit := uint32(1) << (i % wordSize)
p := &(*b)[(i/wordSize)%blockWords]

Expand Down

0 comments on commit c8cf324

Please sign in to comment.