github.com/Psiphon-Inc/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  }