-
Notifications
You must be signed in to change notification settings - Fork 14
Eliminate use of stdlib rand #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,9 @@ import ( | |
| "bytes" | ||
| "encoding/binary" | ||
| "fmt" | ||
| "math/rand" | ||
| "time" | ||
|
|
||
| "github.com/dgryski/go-wyhash" | ||
| ) | ||
|
|
||
| // maxCuckooKickouts is the maximum number of times reinsert | ||
|
|
@@ -18,6 +20,9 @@ type Filter struct { | |
| // Bit mask set to len(buckets) - 1. As len(buckets) is always a power of 2, | ||
| // applying this mask mimics the operation x % len(buckets). | ||
| bucketIndexMask uint | ||
| // rng is a simple pseudo-random number generator that we store locally | ||
| // so that we don't have to spend time locking the global RNG. | ||
| rng *wyhash.Rng | ||
| } | ||
|
|
||
| // NewFilter returns a new cuckoofilter suitable for the given number of elements. | ||
|
|
@@ -33,10 +38,12 @@ func NewFilter(numElements uint) *Filter { | |
| numBuckets = 1 | ||
| } | ||
| buckets := make([]bucket, numBuckets) | ||
| rng := wyhash.Rng(time.Now().UnixNano()) | ||
| return &Filter{ | ||
| buckets: buckets, | ||
| count: 0, | ||
| bucketIndexMask: uint(len(buckets) - 1), | ||
| rng: &rng, | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -72,7 +79,26 @@ func (cf *Filter) Insert(data []byte) bool { | |
| if cf.insert(fp, i2) { | ||
| return true | ||
| } | ||
| return cf.reinsert(fp, randi(i1, i2)) | ||
| return cf.reinsert(fp, cf.Coinflip(i1, i2)) | ||
| } | ||
|
|
||
| // Using % isn't *perfectly* uniform, but it really only matters when n is a | ||
| // significant fraction of the rng's range. It's more than good enough for our | ||
| // purposes since n is on the order of 10^6 and our rng is 63 bits (10^19); this | ||
| // means the bias is on the order of 10^-13. For our use case, that's well below | ||
| // the noise floor. | ||
| func (cf *Filter) Intn(n int) int { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lowercase, no need to make this public |
||
| // we need to make sure it's strictly positive, so mask off the sign bit | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Casting to uint would make this more straight-forward. |
||
| return int(cf.rng.Next()&0x7FFF_FFFF_FFFF_FFFF) % n | ||
| } | ||
|
|
||
| // Coinflip returns either i1 or i2 randomly by examining the least significant | ||
| // bit of the RNG. | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment nit: Coinflip returns either i1 or i2 randomly with about equal chance. The rest is an implementation detail. |
||
| func (cf Filter) Coinflip(i1, i2 uint) uint { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lowercase, no need to make this public. |
||
| if cf.rng.Next()&0x1 == 0 { | ||
| return i1 | ||
| } | ||
| return i2 | ||
| } | ||
|
|
||
| func (cf *Filter) insert(fp fingerprint, i uint) bool { | ||
|
|
@@ -85,7 +111,7 @@ func (cf *Filter) insert(fp fingerprint, i uint) bool { | |
|
|
||
| func (cf *Filter) reinsert(fp fingerprint, i uint) bool { | ||
| for k := 0; k < maxCuckooKickouts; k++ { | ||
| j := rand.Intn(bucketSize) | ||
| j := cf.Intn(bucketSize) | ||
| // Swap fingerprint with bucket entry. | ||
| cf.buckets[i][j], fp = fp, cf.buckets[i][j] | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E= | ||
| github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= | ||
| github.com/dgryski/go-wyhash v0.0.0-20191203203029-c4841ae36371 h1:bz5ApY1kzFBvw3yckuyRBCtqGvprWrKswYK468nm+Gs= | ||
| github.com/dgryski/go-wyhash v0.0.0-20191203203029-c4841ae36371/go.mod h1:/ENMIO1SQeJ5YQeUWWpbX8f+bS8INHrrhFjXgEqi4LA= | ||
| github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | ||
| github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inline here as &wyhash.Rng(time.Now().UnixNano())