71 lines
1.4 KiB
Go
71 lines
1.4 KiB
Go
package pipeline
|
|||
|
|
|
||
|
|
import (
|
||
|
|
mathrand "math/rand/v2"
|
||
|
|
"sync"
|
||
|
|
)
|
||
|
|
|
||
|
|
// stringSample is a memory-bounded queue that keeps a random sample of recent
|
||
|
|
// hostnames instead of a FIFO. A FIFO fills with the first N hostnames seen at
|
||
|
|
// startup and drops everything after, so DNS enrichment only ever sees stale
|
||
|
|
// hostnames and CNAME discovery stalls. Random replacement makes coverage
|
||
|
|
// representative at bounded memory. Not on the certificate hot path.
|
||
|
|
type stringSample struct {
|
||
|
|
mu sync.Mutex
|
||
|
|
items []string
|
||
|
|
cap int
|
||
|
|
notify chan struct{}
|
||
|
|
stop chan struct{}
|
||
|
|
once sync.Once
|
||
|
|
}
|
||
|
|
|
||
|
|
func newStringSample(capacity int) *stringSample {
|
||
|
|
return &stringSample{
|
||
|
|
cap: capacity,
|
||
|
|
notify: make(chan struct{}, 1),
|
||
|
|
stop: make(chan struct{}),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (q *stringSample) push(s string) {
|
||
|
|
q.mu.Lock()
|
||
|
|
if len(q.items) < q.cap {
|
||
|
|
q.items = append(q.items, s)
|
||
|
|
} else {
|
||
|
|
q.items[mathrand.IntN(len(q.items))] = s
|
||
|
|
}
|
||
|
|
q.mu.Unlock()
|
||
|
|
select {
|
||
|
|
case q.notify <- struct{}{}:
|
||
|
|
default:
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (q *stringSample) pop() (string, bool) {
|
||
|
|
q.mu.Lock()
|
||
|
|
n := len(q.items)
|
||
|
|
if n == 0 {
|
||
|
|
q.mu.Unlock()
|
||
|
|
return "", false
|
||
|
|
}
|
||
|
|
i := mathrand.IntN(n)
|
||
|
|
s := q.items[i]
|
||
|
|
q.items[i] = q.items[n-1]
|
||
|
|
q.items = q.items[:n-1]
|
||
|
|
q.mu.Unlock()
|
||
|
|
return s, true
|
||
|
|
}
|
||
|
|
|
||
|
|
func (q *stringSample) len() int {
|
||
|
|
q.mu.Lock()
|
||
|
|
defer q.mu.Unlock()
|
||
|
|
return len(q.items)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (q *stringSample) close() {
|
||
|
|
q.once.Do(func() { close(q.stop) })
|
||
|
|
select {
|
||
|
|
case q.notify <- struct{}{}:
|
||
|
|
default:
|
||
|
|
}
|
||
|
|
}
|