tokenbucket.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package tokenbucket
  2. import (
  3. "sync"
  4. "time"
  5. )
  6. type Bucket struct {
  7. capacity int64
  8. tokens chan struct{}
  9. rate time.Duration // Add a token to the bucket every 1/r units of time
  10. rateMutex sync.Mutex
  11. }
  12. func NewBucket(rate time.Duration, capacity int64) *Bucket {
  13. //A bucket is simply a channel with a buffer representing the maximum size
  14. tokens := make(chan struct{}, capacity)
  15. b := &Bucket{capacity, tokens, rate, sync.Mutex{}}
  16. //Set off a function that will continuously add tokens to the bucket
  17. go func(b *Bucket) {
  18. ticker := time.NewTicker(rate)
  19. for _ = range ticker.C {
  20. b.tokens <- struct{}{}
  21. }
  22. }(b)
  23. return b
  24. }
  25. func (b *Bucket) GetRate() time.Duration {
  26. b.rateMutex.Lock()
  27. tmp := b.rate
  28. b.rateMutex.Unlock()
  29. return tmp
  30. }
  31. func (b *Bucket) SetRate(rate time.Duration) {
  32. b.rateMutex.Lock()
  33. b.rate = rate
  34. b.rateMutex.Unlock()
  35. }
  36. //AddTokens manually adds n tokens to the bucket
  37. func (b *Bucket) AddToken(n int64) {
  38. }
  39. func (b *Bucket) withdrawTokens(n int64) error {
  40. for i := int64(0); i < n; i++ {
  41. <-b.tokens
  42. }
  43. return nil
  44. }
  45. func (b *Bucket) SpendToken(n int64) <-chan error {
  46. // Default to spending a single token
  47. if n < 0 {
  48. n = 1
  49. }
  50. c := make(chan error)
  51. go func(b *Bucket, n int64, c chan error) {
  52. c <- b.withdrawTokens(n)
  53. close(c)
  54. return
  55. }(b, n, c)
  56. return c
  57. }
  58. // Drain will empty all tokens in the bucket
  59. // If the tokens are being added too quickly (if the rate is too fast)
  60. // this will never drain
  61. func (b *Bucket) Drain() error{
  62. // TODO replace this with a more solid approach (such as replacing the channel altogether)
  63. for {
  64. select {
  65. case _ = <-b.tokens:
  66. continue
  67. default:
  68. return nil
  69. }
  70. }
  71. }