52 lignes
983 o
Go
52 lignes
983 o
Go
|
package missinggo
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
"runtime"
|
||
|
"sync"
|
||
|
"sync/atomic"
|
||
|
)
|
||
|
|
||
|
const debug = false
|
||
|
|
||
|
// A Wolf represents some event that becomes less and less interesting as it
|
||
|
// occurs. Call CryHeard to see if we should pay attention this time.
|
||
|
type Wolf struct {
|
||
|
cries uint64
|
||
|
}
|
||
|
|
||
|
// Returns true less and less often. Convenient for exponentially decreasing
|
||
|
// the amount of noise due to errors.
|
||
|
func (me *Wolf) CryHeard() bool {
|
||
|
n := atomic.AddUint64(&me.cries, 1)
|
||
|
return n&(n-1) == 0
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
mu sync.Mutex
|
||
|
wolves map[uintptr]*Wolf
|
||
|
)
|
||
|
|
||
|
// Calls CryHeard() on a Wolf that is unique to the callers program counter.
|
||
|
// i.e. every CryHeard() expression has its own Wolf.
|
||
|
func CryHeard() bool {
|
||
|
pc, file, line, ok := runtime.Caller(1)
|
||
|
if debug {
|
||
|
log.Println(pc, file, line, ok)
|
||
|
}
|
||
|
if !ok {
|
||
|
return true
|
||
|
}
|
||
|
mu.Lock()
|
||
|
if wolves == nil {
|
||
|
wolves = make(map[uintptr]*Wolf)
|
||
|
}
|
||
|
w, ok := wolves[pc]
|
||
|
if !ok {
|
||
|
w = new(Wolf)
|
||
|
wolves[pc] = w
|
||
|
}
|
||
|
mu.Unlock()
|
||
|
return w.CryHeard()
|
||
|
}
|