117 lines
2.1 KiB
Go
117 lines
2.1 KiB
Go
package rolling
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Number tracks a numberBucket over a bounded number of
|
|
// time buckets. Currently the buckets are one second long and only the last 10 seconds are kept.
|
|
type Number struct {
|
|
Buckets map[int64]*numberBucket
|
|
Mutex *sync.RWMutex
|
|
}
|
|
|
|
type numberBucket struct {
|
|
Value float64
|
|
}
|
|
|
|
// NewNumber initializes a RollingNumber struct.
|
|
func NewNumber() *Number {
|
|
r := &Number{
|
|
Buckets: make(map[int64]*numberBucket),
|
|
Mutex: &sync.RWMutex{},
|
|
}
|
|
return r
|
|
}
|
|
|
|
func (r *Number) getCurrentBucket() *numberBucket {
|
|
now := time.Now().Unix()
|
|
var bucket *numberBucket
|
|
var ok bool
|
|
|
|
if bucket, ok = r.Buckets[now]; !ok {
|
|
bucket = &numberBucket{}
|
|
r.Buckets[now] = bucket
|
|
}
|
|
|
|
return bucket
|
|
}
|
|
|
|
func (r *Number) removeOldBuckets() {
|
|
now := time.Now().Unix() - 10
|
|
|
|
for timestamp := range r.Buckets {
|
|
// TODO: configurable rolling window
|
|
if timestamp <= now {
|
|
delete(r.Buckets, timestamp)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Increment increments the number in current timeBucket.
|
|
func (r *Number) Increment(i float64) {
|
|
if i == 0 {
|
|
return
|
|
}
|
|
|
|
r.Mutex.Lock()
|
|
defer r.Mutex.Unlock()
|
|
|
|
b := r.getCurrentBucket()
|
|
b.Value += i
|
|
r.removeOldBuckets()
|
|
}
|
|
|
|
// UpdateMax updates the maximum value in the current bucket.
|
|
func (r *Number) UpdateMax(n float64) {
|
|
r.Mutex.Lock()
|
|
defer r.Mutex.Unlock()
|
|
|
|
b := r.getCurrentBucket()
|
|
if n > b.Value {
|
|
b.Value = n
|
|
}
|
|
r.removeOldBuckets()
|
|
}
|
|
|
|
// Sum sums the values over the buckets in the last 10 seconds.
|
|
func (r *Number) Sum(now time.Time) float64 {
|
|
sum := float64(0)
|
|
|
|
r.Mutex.RLock()
|
|
defer r.Mutex.RUnlock()
|
|
|
|
for timestamp, bucket := range r.Buckets {
|
|
// TODO: configurable rolling window
|
|
if timestamp >= now.Unix()-10 {
|
|
sum += bucket.Value
|
|
}
|
|
}
|
|
|
|
return sum
|
|
}
|
|
|
|
// Max returns the maximum value seen in the last 10 seconds.
|
|
func (r *Number) Max(now time.Time) float64 {
|
|
var max float64
|
|
|
|
r.Mutex.RLock()
|
|
defer r.Mutex.RUnlock()
|
|
|
|
for timestamp, bucket := range r.Buckets {
|
|
// TODO: configurable rolling window
|
|
if timestamp >= now.Unix()-10 {
|
|
if bucket.Value > max {
|
|
max = bucket.Value
|
|
}
|
|
}
|
|
}
|
|
|
|
return max
|
|
}
|
|
|
|
func (r *Number) Avg(now time.Time) float64 {
|
|
return r.Sum(now) / 10
|
|
}
|