-
Notifications
You must be signed in to change notification settings - Fork 1
/
sample.go
99 lines (90 loc) · 2.29 KB
/
sample.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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Package errorsample samples error values
// uniformly at random
// from an unbounded set of inputs.
// It provides a representative sample
// when the total amount of errors
// is too many to store.
//
// Functions in this package are safe to call concurrently.
package errorsample // import "github.com/kr/errorsample"
import (
"math/rand"
"sync"
)
// Set represents an unbounded set of errors.
// Its Sample method returns a sample of bounded size,
// chosen uniformly at random from the set.
//
// Its methods are safe to call concurrently.
// The zero value of Set is a set
// with a capacity of 0.
type Set struct {
mu sync.Mutex
n int
buf []error // slice header is constant
}
// New returns a new Set
// that samples up to cap errors.
func New(cap int) *Set {
return &Set{buf: make([]error, cap)}
}
// Reset removes all errors from s.
func (s *Set) Reset() {
s.mu.Lock()
defer s.mu.Unlock()
s.n = 0
}
// Add adds err to s.
func (s *Set) Add(err error) {
s.mu.Lock()
defer s.mu.Unlock()
if len(s.buf) < 1 {
} else if s.n < len(s.buf) {
s.buf[s.n] = err
} else if i := rand.Intn(s.n); i < len(s.buf) {
// Sample this item with prob. len(s.buf)/s.n.
// Replace an existing sample with prob. 1/len(s.buf).
// See Jeffrey S. Vitter, Random sampling with a reservoir,
// ACM Trans. Math. Softw. 11 (1985), no. 1, 37–57.
s.buf[i] = err
}
s.n++
}
// Sample reads into p a uniform random sample
// of error values from s.
// It will not read more than the capacity of s.
// It also will not read more errors
// than have been added
// since the last call to Reset.
//
// It returns the number of errors read.
//
// Repeated calls to Sample are not random
// with respect to each other,
// only with respect to
// the sequence of errors added to s.
// In particular, two successive calls to Sample
// with no intervening Add or Reset
// will produce the same sample.
func (s *Set) Sample(p []error) int {
s.mu.Lock()
defer s.mu.Unlock()
b := s.buf
if s.n < len(b) {
b = b[:s.n]
}
return copy(p, b)
}
// Cap returns the capacity of s.
// Sample will return at most
// this many errors.
func (s *Set) Cap() int {
return len(s.buf)
}
// Added returns the number of errors added to s
// since the last call to Reset.
func (s *Set) Added() int {
s.mu.Lock()
defer s.mu.Unlock()
return s.n
}