l.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package alloclim
  2. import "sync"
  3. // Manages reservations sharing a common allocation limit.
  4. type Limiter struct {
  5. // Maximum outstanding allocation space.
  6. Max int64
  7. initOnce sync.Once
  8. mu sync.Mutex
  9. // Current unallocated space.
  10. value int64
  11. // Reservations waiting to in the order they arrived.
  12. waiting []*Reservation
  13. }
  14. func (me *Limiter) initValue() {
  15. me.value = me.Max
  16. }
  17. func (me *Limiter) init() {
  18. me.initOnce.Do(func() {
  19. me.initValue()
  20. })
  21. }
  22. func (me *Limiter) Reserve(n int64) *Reservation {
  23. r := &Reservation{
  24. l: me,
  25. n: n,
  26. }
  27. me.init()
  28. me.mu.Lock()
  29. if n <= me.value {
  30. me.value -= n
  31. r.granted.Set()
  32. } else {
  33. me.waiting = append(me.waiting, r)
  34. }
  35. me.mu.Unlock()
  36. return r
  37. }
  38. func (me *Limiter) doWakesLocked() {
  39. for {
  40. if len(me.waiting) == 0 {
  41. break
  42. }
  43. r := me.waiting[0]
  44. switch {
  45. case r.cancelled.IsSet():
  46. case r.n <= me.value:
  47. if r.wake() {
  48. me.value -= r.n
  49. }
  50. default:
  51. return
  52. }
  53. me.waiting = me.waiting[1:]
  54. }
  55. }
  56. func (me *Limiter) doWakes() {
  57. me.mu.Lock()
  58. me.doWakesLocked()
  59. me.mu.Unlock()
  60. }
  61. func (me *Limiter) addValue(n int64) {
  62. me.mu.Lock()
  63. me.value += n
  64. me.doWakesLocked()
  65. me.mu.Unlock()
  66. }
  67. func (me *Limiter) Value() int64 {
  68. me.mu.Lock()
  69. defer me.mu.Unlock()
  70. return me.value
  71. }