-
Notifications
You must be signed in to change notification settings - Fork 0
/
decrement.go
61 lines (53 loc) · 1.38 KB
/
decrement.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package sample
import (
"errors"
"fmt"
"math/rand"
"time"
)
// Decrement is a Sampler, which samples if the counter, initialized by a random number, is decremented to 0
type decrement struct {
sampleState
count uint64
}
// NewDecrement returns a Decrement Sampler, random number generator is seeded with UnixNano
func NewDecrement(rate uint64) (Sampler, error) {
return NewDecrementSeeded(rate, time.Now().UTC().UnixNano())
}
// NewDecrementSeeded returns a Decrement Sampler, allow for manual seeding of the random number generator
func NewDecrementSeeded(rate uint64, seed int64) (Sampler, error) {
if rate == 0 {
return nil, errors.New("rate must not be 0")
}
rnd := rand.New(rand.NewSource(seed))
return &decrement{sampleState: sampleState{rate: rate, seed: seed, rnd: rnd}, count: decrementSeed(rnd, rate)}, nil
}
func (dec *decrement) Sample() bool {
dec.sampleCount++
if dec.count == 0 {
dec.trueCount++
dec.count = decrementSeed(dec.rnd, dec.rate)
return true
}
dec.count--
return false
}
func (dec *decrement) SampleFrom(probe uint64) bool {
dec.sampleCount++
if probe%dec.rate == 0 {
dec.trueCount++
return true
}
return false
}
func (dec *decrement) String() string {
type X *decrement
x := X(dec)
return fmt.Sprintf("%+v", x)
}
func decrementSeed(rnd *rand.Rand, rate uint64) uint64 {
if rate == 1 {
return 0
}
return randUint64(rnd) % (rate*2 - 2)
}