github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/common/timer.go (about) 1 package common 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 type TimingWheel struct { 9 sync.Mutex 10 11 interval time.Duration 12 13 ticker *time.Ticker 14 quit chan struct{} 15 16 maxTimeout time.Duration 17 18 cs []chan struct{} 19 20 pos int 21 } 22 23 func NewTimingWheel(interval time.Duration, buckets int) *TimingWheel { 24 w := new(TimingWheel) 25 26 w.interval = interval 27 28 w.quit = make(chan struct{}) 29 w.pos = 0 30 31 w.maxTimeout = time.Duration(interval * (time.Duration(buckets))) 32 33 w.cs = make([]chan struct{}, buckets) 34 35 for i := range w.cs { 36 w.cs[i] = make(chan struct{}) 37 } 38 39 w.ticker = time.NewTicker(interval) 40 go w.run() 41 42 return w 43 } 44 45 func (w *TimingWheel) Stop() { 46 close(w.quit) 47 } 48 49 func (w *TimingWheel) After(timeout time.Duration) <-chan struct{} { 50 if timeout >= w.maxTimeout { 51 panic("timeout too much, over maxtimeout") 52 } 53 54 index := int(timeout / w.interval) 55 if 0 < index { 56 index-- 57 } 58 59 w.Lock() 60 61 index = (w.pos + index) % len(w.cs) 62 63 b := w.cs[index] 64 65 w.Unlock() 66 67 return b 68 } 69 70 func (w *TimingWheel) run() { 71 for { 72 select { 73 case <-w.ticker.C: 74 w.onTicker() 75 case <-w.quit: 76 w.ticker.Stop() 77 return 78 } 79 } 80 } 81 82 func (w *TimingWheel) onTicker() { 83 w.Lock() 84 85 lastC := w.cs[w.pos] 86 w.cs[w.pos] = make(chan struct{}) 87 88 w.pos = (w.pos + 1) % len(w.cs) 89 90 w.Unlock() 91 92 close(lastC) 93 }