Vendor main dependencies.
This commit is contained in:
parent
49a09ab7dd
commit
dd5e3fba01
2738 changed files with 1045689 additions and 0 deletions
155
vendor/github.com/vulcand/oxy/memmetrics/counter.go
generated
vendored
Normal file
155
vendor/github.com/vulcand/oxy/memmetrics/counter.go
generated
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
package memmetrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mailgun/timetools"
|
||||
)
|
||||
|
||||
type rcOptSetter func(*RollingCounter) error
|
||||
|
||||
func CounterClock(c timetools.TimeProvider) rcOptSetter {
|
||||
return func(r *RollingCounter) error {
|
||||
r.clock = c
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Calculates in memory failure rate of an endpoint using rolling window of a predefined size
|
||||
type RollingCounter struct {
|
||||
clock timetools.TimeProvider
|
||||
resolution time.Duration
|
||||
values []int
|
||||
countedBuckets int // how many samples in different buckets have we collected so far
|
||||
lastBucket int // last recorded bucket
|
||||
lastUpdated time.Time
|
||||
}
|
||||
|
||||
// NewCounter creates a counter with fixed amount of buckets that are rotated every resolution period.
|
||||
// E.g. 10 buckets with 1 second means that every new second the bucket is refreshed, so it maintains 10 second rolling window.
|
||||
// By default creates a bucket with 10 buckets and 1 second resolution
|
||||
func NewCounter(buckets int, resolution time.Duration, options ...rcOptSetter) (*RollingCounter, error) {
|
||||
if buckets <= 0 {
|
||||
return nil, fmt.Errorf("Buckets should be >= 0")
|
||||
}
|
||||
if resolution < time.Second {
|
||||
return nil, fmt.Errorf("Resolution should be larger than a second")
|
||||
}
|
||||
|
||||
rc := &RollingCounter{
|
||||
lastBucket: -1,
|
||||
resolution: resolution,
|
||||
|
||||
values: make([]int, buckets),
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
if err := o(rc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if rc.clock == nil {
|
||||
rc.clock = &timetools.RealTime{}
|
||||
}
|
||||
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
func (c *RollingCounter) Append(o *RollingCounter) error {
|
||||
c.Inc(int(o.Count()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RollingCounter) Clone() *RollingCounter {
|
||||
c.cleanup()
|
||||
other := &RollingCounter{
|
||||
resolution: c.resolution,
|
||||
values: make([]int, len(c.values)),
|
||||
clock: c.clock,
|
||||
lastBucket: c.lastBucket,
|
||||
lastUpdated: c.lastUpdated,
|
||||
}
|
||||
for i, v := range c.values {
|
||||
other.values[i] = v
|
||||
}
|
||||
return other
|
||||
}
|
||||
|
||||
func (c *RollingCounter) Reset() {
|
||||
c.lastBucket = -1
|
||||
c.countedBuckets = 0
|
||||
c.lastUpdated = time.Time{}
|
||||
for i := range c.values {
|
||||
c.values[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RollingCounter) CountedBuckets() int {
|
||||
return c.countedBuckets
|
||||
}
|
||||
|
||||
func (c *RollingCounter) Count() int64 {
|
||||
c.cleanup()
|
||||
return c.sum()
|
||||
}
|
||||
|
||||
func (c *RollingCounter) Resolution() time.Duration {
|
||||
return c.resolution
|
||||
}
|
||||
|
||||
func (c *RollingCounter) Buckets() int {
|
||||
return len(c.values)
|
||||
}
|
||||
|
||||
func (c *RollingCounter) WindowSize() time.Duration {
|
||||
return time.Duration(len(c.values)) * c.resolution
|
||||
}
|
||||
|
||||
func (c *RollingCounter) Inc(v int) {
|
||||
c.cleanup()
|
||||
c.incBucketValue(v)
|
||||
}
|
||||
|
||||
func (c *RollingCounter) incBucketValue(v int) {
|
||||
now := c.clock.UtcNow()
|
||||
bucket := c.getBucket(now)
|
||||
c.values[bucket] += v
|
||||
c.lastUpdated = now
|
||||
// Update usage stats if we haven't collected enough data
|
||||
if c.countedBuckets < len(c.values) {
|
||||
// Only update if we have advanced to the next bucket and not incremented the value
|
||||
// in the current bucket.
|
||||
if c.lastBucket != bucket {
|
||||
c.lastBucket = bucket
|
||||
c.countedBuckets++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number in the moving window bucket that this slot occupies
|
||||
func (c *RollingCounter) getBucket(t time.Time) int {
|
||||
return int(t.Truncate(c.resolution).Unix() % int64(len(c.values)))
|
||||
}
|
||||
|
||||
// Reset buckets that were not updated
|
||||
func (c *RollingCounter) cleanup() {
|
||||
now := c.clock.UtcNow()
|
||||
for i := 0; i < len(c.values); i++ {
|
||||
now = now.Add(time.Duration(-1*i) * c.resolution)
|
||||
if now.Truncate(c.resolution).After(c.lastUpdated.Truncate(c.resolution)) {
|
||||
c.values[c.getBucket(now)] = 0
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RollingCounter) sum() int64 {
|
||||
out := int64(0)
|
||||
for _, v := range c.values {
|
||||
out += int64(v)
|
||||
}
|
||||
return out
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue