influxdb/timer.go

174 lines
4.1 KiB
Go
Raw Normal View History

2013-04-28 21:23:21 +00:00
package raft
import (
"math/rand"
"sync"
"time"
)
//------------------------------------------------------------------------------
//
// Typedefs
//
//------------------------------------------------------------------------------
2013-05-05 20:01:06 +00:00
// The timer wraps the internal Go timer and provides the ability to pause,
// reset and stop. It also allows for the duration of the timer to be a random
// number between a min and max duration.
type Timer struct {
2013-05-27 02:06:08 +00:00
c chan time.Time
2013-05-27 00:02:31 +00:00
// Used to break the goroutine listening for the internalTimer since the
// Timer struct won't close its channel automatically.
resetChannel chan bool
2013-04-28 21:23:21 +00:00
rand *rand.Rand
2013-05-05 20:01:06 +00:00
minDuration time.Duration
maxDuration time.Duration
2013-04-28 21:23:21 +00:00
internalTimer *time.Timer
mutex sync.Mutex
}
//------------------------------------------------------------------------------
//
// Constructors
//
//------------------------------------------------------------------------------
// Creates a new timer. Panics if a non-positive duration is used.
2013-05-05 20:01:06 +00:00
func NewTimer(minDuration time.Duration, maxDuration time.Duration) *Timer {
if minDuration <= 0 {
panic("raft.Timer: Non-positive minimum duration not allowed")
2013-04-28 21:23:21 +00:00
}
2013-05-05 20:01:06 +00:00
if maxDuration <= 0 {
panic("raft.Timer: Non-positive maximum duration not allowed")
}
if minDuration > maxDuration {
panic("raft.Timer: Minimum duration cannot be greater than maximum duration")
}
return &Timer{
2013-05-27 02:06:08 +00:00
c: make(chan time.Time, 1),
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
minDuration: minDuration,
maxDuration: maxDuration,
2013-04-28 21:23:21 +00:00
}
}
2013-05-01 05:21:56 +00:00
//------------------------------------------------------------------------------
//
// Accessors
//
//------------------------------------------------------------------------------
// Retrieves the timer's channel.
func (t *Timer) C() chan time.Time {
t.mutex.Lock()
defer t.mutex.Unlock()
return t.c
}
2013-05-05 20:01:06 +00:00
// Retrieves the minimum duration of the timer.
func (t *Timer) MinDuration() time.Duration {
return t.minDuration
}
// Sets the minimum duration of the timer.
func (t *Timer) SetMinDuration(duration time.Duration) {
t.minDuration = duration
t.Reset()
}
// Retrieves the maximum duration of the timer.
func (t *Timer) MaxDuration() time.Duration {
return t.maxDuration
2013-05-01 05:21:56 +00:00
}
2013-05-05 20:01:06 +00:00
// Sets the maximum duration of the timer.
func (t *Timer) SetMaxDuration(duration time.Duration) {
t.maxDuration = duration
2013-05-01 05:21:56 +00:00
t.Reset()
}
2013-05-05 20:26:04 +00:00
// Sets the minimum and maximum duration of the timer.
func (t *Timer) SetDuration(duration time.Duration) {
t.minDuration = duration
t.maxDuration = duration
t.Reset()
}
2013-04-28 21:23:21 +00:00
//------------------------------------------------------------------------------
//
// Methods
//
//------------------------------------------------------------------------------
// Checks if the timer is currently running.
2013-05-05 20:01:06 +00:00
func (t *Timer) Running() bool {
2013-04-28 21:23:21 +00:00
return t.internalTimer != nil
}
// Stops the timer and closes the channel.
2013-05-05 20:01:06 +00:00
func (t *Timer) Stop() {
2013-04-28 21:23:21 +00:00
t.mutex.Lock()
defer t.mutex.Unlock()
2013-05-27 00:02:31 +00:00
t.stopInternalTimer()
2013-04-28 21:23:21 +00:00
if t.c != nil {
close(t.c)
t.c = nil
2013-04-28 21:23:21 +00:00
}
}
// Stops the timer.
2013-05-05 20:01:06 +00:00
func (t *Timer) Pause() {
2013-04-28 21:23:21 +00:00
t.mutex.Lock()
defer t.mutex.Unlock()
2013-05-27 00:02:31 +00:00
t.stopInternalTimer()
}
// Stops the timer and closes the channel.
func (t *Timer) stopInternalTimer() {
2013-04-28 21:23:21 +00:00
if t.internalTimer != nil {
t.internalTimer.Stop()
t.internalTimer = nil
2013-05-27 00:02:31 +00:00
close(t.resetChannel)
t.resetChannel = nil
2013-04-28 21:23:21 +00:00
}
}
// Stops the timer if it is running and restarts it.
2013-05-05 20:01:06 +00:00
func (t *Timer) Reset() {
2013-04-28 21:23:21 +00:00
t.mutex.Lock()
defer t.mutex.Unlock()
// Stop the timer if it's already running.
if t.internalTimer != nil {
2013-05-27 00:02:31 +00:00
t.stopInternalTimer()
2013-04-28 21:23:21 +00:00
}
2013-05-05 20:01:06 +00:00
// Start a timer that will go off between the min and max duration.
d := t.minDuration
if t.maxDuration > t.minDuration {
2013-05-10 14:47:24 +00:00
d += time.Duration(t.rand.Int63n(int64(t.maxDuration - t.minDuration)))
}
2013-04-28 21:23:21 +00:00
t.internalTimer = time.NewTimer(d)
2013-05-27 00:02:31 +00:00
t.resetChannel = make(chan bool, 1)
internalTimer, resetChannel := t.internalTimer, t.resetChannel
2013-04-28 21:23:21 +00:00
go func() {
2013-05-05 20:01:06 +00:00
// If the timer exists then grab the value from the channel and pass
// it through to the timer's external channel.
2013-05-27 00:02:31 +00:00
select {
case v, ok := <-internalTimer.C:
if ok {
2013-05-05 19:48:15 +00:00
t.mutex.Lock()
2013-06-03 23:16:50 +00:00
if t.c != nil {
t.c <- v
}
2013-05-05 19:48:15 +00:00
t.mutex.Unlock()
2013-04-28 21:23:21 +00:00
}
2013-05-27 00:02:31 +00:00
case <-resetChannel:
2013-04-28 21:23:21 +00:00
}
}()
}