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  }