github.com/Psiphon-Labs/goarista@v0.0.0-20160825065156-d002785f4c67/monitor/stats/tracker.go (about) 1 package stats 2 3 import ( 4 "math" 5 "sync" 6 "time" 7 ) 8 9 // Tracker is a min/max value tracker that keeps track of its min/max values 10 // over a given period of time, and with a given resolution. The initial min 11 // and max values are math.MaxInt64 and math.MinInt64 respectively. 12 type Tracker struct { 13 mu sync.RWMutex 14 min, max int64 // All time min/max. 15 minTS, maxTS [3]*timeseries 16 lastUpdate time.Time 17 } 18 19 // newTracker returns a new Tracker. 20 func newTracker() *Tracker { 21 now := TimeNow() 22 t := &Tracker{} 23 t.minTS[hour] = newTimeSeries(now, time.Hour, time.Minute) 24 t.minTS[tenminutes] = newTimeSeries(now, 10*time.Minute, 10*time.Second) 25 t.minTS[minute] = newTimeSeries(now, time.Minute, time.Second) 26 t.maxTS[hour] = newTimeSeries(now, time.Hour, time.Minute) 27 t.maxTS[tenminutes] = newTimeSeries(now, 10*time.Minute, 10*time.Second) 28 t.maxTS[minute] = newTimeSeries(now, time.Minute, time.Second) 29 t.init() 30 return t 31 } 32 33 func (t *Tracker) init() { 34 t.min = math.MaxInt64 35 t.max = math.MinInt64 36 for _, ts := range t.minTS { 37 ts.set(math.MaxInt64) 38 } 39 for _, ts := range t.maxTS { 40 ts.set(math.MinInt64) 41 } 42 } 43 44 func (t *Tracker) advance() time.Time { 45 now := TimeNow() 46 for _, ts := range t.minTS { 47 ts.advanceTimeWithFill(now, math.MaxInt64) 48 } 49 for _, ts := range t.maxTS { 50 ts.advanceTimeWithFill(now, math.MinInt64) 51 } 52 return now 53 } 54 55 // LastUpdate returns the last update time of the range. 56 func (t *Tracker) LastUpdate() time.Time { 57 t.mu.RLock() 58 defer t.mu.RUnlock() 59 return t.lastUpdate 60 } 61 62 // Push adds a new value if it is a new minimum or maximum. 63 func (t *Tracker) Push(value int64) { 64 t.mu.Lock() 65 defer t.mu.Unlock() 66 t.lastUpdate = t.advance() 67 if t.min > value { 68 t.min = value 69 } 70 if t.max < value { 71 t.max = value 72 } 73 for _, ts := range t.minTS { 74 if ts.headValue() > value { 75 ts.set(value) 76 } 77 } 78 for _, ts := range t.maxTS { 79 if ts.headValue() < value { 80 ts.set(value) 81 } 82 } 83 } 84 85 // Min returns the minimum value of the tracker 86 func (t *Tracker) Min() int64 { 87 t.mu.RLock() 88 defer t.mu.RUnlock() 89 return t.min 90 } 91 92 // Max returns the maximum value of the tracker. 93 func (t *Tracker) Max() int64 { 94 t.mu.RLock() 95 defer t.mu.RUnlock() 96 return t.max 97 } 98 99 // Min1h returns the minimum value for the last hour. 100 func (t *Tracker) Min1h() int64 { 101 t.mu.Lock() 102 defer t.mu.Unlock() 103 t.advance() 104 return t.minTS[hour].min() 105 } 106 107 // Max1h returns the maximum value for the last hour. 108 func (t *Tracker) Max1h() int64 { 109 t.mu.Lock() 110 defer t.mu.Unlock() 111 t.advance() 112 return t.maxTS[hour].max() 113 } 114 115 // Min10m returns the minimum value for the last 10 minutes. 116 func (t *Tracker) Min10m() int64 { 117 t.mu.Lock() 118 defer t.mu.Unlock() 119 t.advance() 120 return t.minTS[tenminutes].min() 121 } 122 123 // Max10m returns the maximum value for the last 10 minutes. 124 func (t *Tracker) Max10m() int64 { 125 t.mu.Lock() 126 defer t.mu.Unlock() 127 t.advance() 128 return t.maxTS[tenminutes].max() 129 } 130 131 // Min1m returns the minimum value for the last 1 minute. 132 func (t *Tracker) Min1m() int64 { 133 t.mu.Lock() 134 defer t.mu.Unlock() 135 t.advance() 136 return t.minTS[minute].min() 137 } 138 139 // Max1m returns the maximum value for the last 1 minute. 140 func (t *Tracker) Max1m() int64 { 141 t.mu.Lock() 142 defer t.mu.Unlock() 143 t.advance() 144 return t.maxTS[minute].max() 145 } 146 147 // Reset resets the range to an empty state. 148 func (t *Tracker) Reset() { 149 t.mu.Lock() 150 defer t.mu.Unlock() 151 now := TimeNow() 152 for _, ts := range t.minTS { 153 ts.reset(now) 154 } 155 for _, ts := range t.maxTS { 156 ts.reset(now) 157 } 158 t.init() 159 }