You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

62 lines
1.3 KiB

9 years ago
9 years ago
  1. package common
  2. import (
  3. "sync/atomic"
  4. "time"
  5. )
  6. /*
  7. ThrottleTimer fires an event at most "dur" after each .Set() call.
  8. If a short burst of .Set() calls happens, ThrottleTimer fires once.
  9. If a long continuous burst of .Set() calls happens, ThrottleTimer fires
  10. at most once every "dur".
  11. */
  12. type ThrottleTimer struct {
  13. Name string
  14. Ch chan struct{}
  15. quit chan struct{}
  16. dur time.Duration
  17. timer *time.Timer
  18. isSet uint32
  19. }
  20. func NewThrottleTimer(name string, dur time.Duration) *ThrottleTimer {
  21. var ch = make(chan struct{})
  22. var quit = make(chan struct{})
  23. var t = &ThrottleTimer{Name: name, Ch: ch, dur: dur, quit: quit}
  24. t.timer = time.AfterFunc(dur, t.fireRoutine)
  25. t.timer.Stop()
  26. return t
  27. }
  28. func (t *ThrottleTimer) fireRoutine() {
  29. select {
  30. case t.Ch <- struct{}{}:
  31. atomic.StoreUint32(&t.isSet, 0)
  32. case <-t.quit:
  33. // do nothing
  34. default:
  35. t.timer.Reset(t.dur)
  36. }
  37. }
  38. func (t *ThrottleTimer) Set() {
  39. if atomic.CompareAndSwapUint32(&t.isSet, 0, 1) {
  40. t.timer.Reset(t.dur)
  41. }
  42. }
  43. func (t *ThrottleTimer) Unset() {
  44. atomic.StoreUint32(&t.isSet, 0)
  45. t.timer.Stop()
  46. }
  47. // For ease of .Stop()'ing services before .Start()'ing them,
  48. // we ignore .Stop()'s on nil ThrottleTimers
  49. func (t *ThrottleTimer) Stop() bool {
  50. if t == nil {
  51. return false
  52. }
  53. close(t.quit)
  54. return t.timer.Stop()
  55. }