glusterfs_minmax.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. //
  14. // This implementation is space-efficient for a sparse
  15. // allocation over a big range. Could be optimized
  16. // for high absolute allocation number with a bitmap.
  17. //
  18. package glusterfs
  19. import (
  20. "errors"
  21. "sync"
  22. )
  23. var (
  24. //ErrConflict returned when value is already in use.
  25. ErrConflict = errors.New("number already allocated")
  26. //ErrInvalidRange returned invalid range, for eg# min > max
  27. ErrInvalidRange = errors.New("invalid range")
  28. //ErrOutOfRange returned when value is not in pool range.
  29. ErrOutOfRange = errors.New("out of range")
  30. //ErrRangeFull returned when no more free values in the pool.
  31. ErrRangeFull = errors.New("range full")
  32. //ErrInternal returned when no free item found, but a.free != 0.
  33. ErrInternal = errors.New("internal error")
  34. )
  35. //MinMaxAllocator defines allocator struct.
  36. type MinMaxAllocator struct {
  37. lock sync.Mutex
  38. min int
  39. max int
  40. free int
  41. used map[int]bool
  42. }
  43. var _ Rangeable = &MinMaxAllocator{}
  44. // Rangeable is an Interface that can adjust its min/max range.
  45. // Rangeable should be threadsafe
  46. type Rangeable interface {
  47. Allocate(int) (bool, error)
  48. AllocateNext() (int, bool, error)
  49. Release(int) error
  50. Has(int) bool
  51. Free() int
  52. SetRange(min, max int) error
  53. }
  54. // NewMinMaxAllocator return a new allocator or error based on provided min/max value.
  55. func NewMinMaxAllocator(min, max int) (*MinMaxAllocator, error) {
  56. if min > max {
  57. return nil, ErrInvalidRange
  58. }
  59. return &MinMaxAllocator{
  60. min: min,
  61. max: max,
  62. free: 1 + max - min,
  63. used: map[int]bool{},
  64. }, nil
  65. }
  66. //SetRange defines the range/pool with provided min and max values.
  67. func (a *MinMaxAllocator) SetRange(min, max int) error {
  68. if min > max {
  69. return ErrInvalidRange
  70. }
  71. a.lock.Lock()
  72. defer a.lock.Unlock()
  73. // Check if we need to change
  74. if a.min == min && a.max == max {
  75. return nil
  76. }
  77. a.min = min
  78. a.max = max
  79. // Recompute how many free we have in the range
  80. numUsed := 0
  81. for i := range a.used {
  82. if a.inRange(i) {
  83. numUsed++
  84. }
  85. }
  86. a.free = 1 + max - min - numUsed
  87. return nil
  88. }
  89. //Allocate allocates provided value in the allocator and mark it as used.
  90. func (a *MinMaxAllocator) Allocate(i int) (bool, error) {
  91. a.lock.Lock()
  92. defer a.lock.Unlock()
  93. if !a.inRange(i) {
  94. return false, ErrOutOfRange
  95. }
  96. if a.has(i) {
  97. return false, ErrConflict
  98. }
  99. a.used[i] = true
  100. a.free--
  101. return true, nil
  102. }
  103. //AllocateNext allocates next value from the allocator.
  104. func (a *MinMaxAllocator) AllocateNext() (int, bool, error) {
  105. a.lock.Lock()
  106. defer a.lock.Unlock()
  107. // Fast check if we're out of items
  108. if a.free <= 0 {
  109. return 0, false, ErrRangeFull
  110. }
  111. // Scan from the minimum until we find a free item
  112. for i := a.min; i <= a.max; i++ {
  113. if !a.has(i) {
  114. a.used[i] = true
  115. a.free--
  116. return i, true, nil
  117. }
  118. }
  119. // no free item found, but a.free != 0
  120. return 0, false, ErrInternal
  121. }
  122. //Release free/delete provided value from the allocator.
  123. func (a *MinMaxAllocator) Release(i int) error {
  124. a.lock.Lock()
  125. defer a.lock.Unlock()
  126. if !a.has(i) {
  127. return nil
  128. }
  129. delete(a.used, i)
  130. if a.inRange(i) {
  131. a.free++
  132. }
  133. return nil
  134. }
  135. func (a *MinMaxAllocator) has(i int) bool {
  136. _, ok := a.used[i]
  137. return ok
  138. }
  139. //Has check whether the provided value is used in the allocator
  140. func (a *MinMaxAllocator) Has(i int) bool {
  141. a.lock.Lock()
  142. defer a.lock.Unlock()
  143. return a.has(i)
  144. }
  145. //Free returns the number of free values in the allocator.
  146. func (a *MinMaxAllocator) Free() int {
  147. a.lock.Lock()
  148. defer a.lock.Unlock()
  149. return a.free
  150. }
  151. func (a *MinMaxAllocator) inRange(i int) bool {
  152. return a.min <= i && i <= a.max
  153. }