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.

195 lines
4.5 KiB

7 years ago
  1. package needle
  2. import (
  3. . "github.com/chrislusf/seaweedfs/weed/storage/types"
  4. "sync"
  5. )
  6. type CompactSection struct {
  7. sync.RWMutex
  8. values []NeedleValue
  9. overflow map[NeedleId]NeedleValue
  10. start NeedleId
  11. end NeedleId
  12. counter int
  13. }
  14. func NewCompactSection(start NeedleId) *CompactSection {
  15. return &CompactSection{
  16. values: make([]NeedleValue, batch),
  17. overflow: make(map[NeedleId]NeedleValue),
  18. start: start,
  19. }
  20. }
  21. //return old entry size
  22. func (cs *CompactSection) Set(key NeedleId, offset Offset, size uint32) (oldOffset Offset, oldSize uint32) {
  23. cs.Lock()
  24. if key > cs.end {
  25. cs.end = key
  26. }
  27. if i := cs.binarySearchValues(key); i >= 0 {
  28. oldOffset, oldSize = cs.values[i].Offset, cs.values[i].Size
  29. //println("key", key, "old size", ret)
  30. cs.values[i].Offset, cs.values[i].Size = offset, size
  31. } else {
  32. needOverflow := cs.counter >= batch
  33. needOverflow = needOverflow || cs.counter > 0 && cs.values[cs.counter-1].Key > key
  34. if needOverflow {
  35. //println("start", cs.start, "counter", cs.counter, "key", key)
  36. if oldValue, found := cs.overflow[key]; found {
  37. oldOffset, oldSize = oldValue.Offset, oldValue.Size
  38. }
  39. cs.overflow[key] = NeedleValue{Key: key, Offset: offset, Size: size}
  40. } else {
  41. p := &cs.values[cs.counter]
  42. p.Key, p.Offset, p.Size = key, offset, size
  43. //println("added index", cs.counter, "key", key, cs.values[cs.counter].Key)
  44. cs.counter++
  45. }
  46. }
  47. cs.Unlock()
  48. return
  49. }
  50. //return old entry size
  51. func (cs *CompactSection) Delete(key NeedleId) uint32 {
  52. cs.Lock()
  53. ret := uint32(0)
  54. if i := cs.binarySearchValues(key); i >= 0 {
  55. if cs.values[i].Size > 0 {
  56. ret = cs.values[i].Size
  57. cs.values[i].Size = 0
  58. }
  59. }
  60. if v, found := cs.overflow[key]; found {
  61. delete(cs.overflow, key)
  62. ret = v.Size
  63. }
  64. cs.Unlock()
  65. return ret
  66. }
  67. func (cs *CompactSection) Get(key NeedleId) (*NeedleValue, bool) {
  68. cs.RLock()
  69. if v, ok := cs.overflow[key]; ok {
  70. cs.RUnlock()
  71. return &v, true
  72. }
  73. if i := cs.binarySearchValues(key); i >= 0 {
  74. cs.RUnlock()
  75. return &cs.values[i], true
  76. }
  77. cs.RUnlock()
  78. return nil, false
  79. }
  80. func (cs *CompactSection) binarySearchValues(key NeedleId) int {
  81. l, h := 0, cs.counter-1
  82. if h >= 0 && cs.values[h].Key < key {
  83. return -2
  84. }
  85. //println("looking for key", key)
  86. for l <= h {
  87. m := (l + h) / 2
  88. //println("mid", m, "key", cs.values[m].Key, cs.values[m].Offset, cs.values[m].Size)
  89. if cs.values[m].Key < key {
  90. l = m + 1
  91. } else if key < cs.values[m].Key {
  92. h = m - 1
  93. } else {
  94. //println("found", m)
  95. return m
  96. }
  97. }
  98. return -1
  99. }
  100. //This map assumes mostly inserting increasing keys
  101. //This map assumes mostly inserting increasing keys
  102. type CompactMap struct {
  103. list []*CompactSection
  104. }
  105. func NewCompactMap() *CompactMap {
  106. return &CompactMap{}
  107. }
  108. func (cm *CompactMap) Set(key NeedleId, offset Offset, size uint32) (oldOffset Offset, oldSize uint32) {
  109. x := cm.binarySearchCompactSection(key)
  110. if x < 0 {
  111. //println(x, "creating", len(cm.list), "section, starting", key)
  112. cm.list = append(cm.list, NewCompactSection(key))
  113. x = len(cm.list) - 1
  114. //keep compact section sorted by start
  115. for x > 0 {
  116. if cm.list[x-1].start > cm.list[x].start {
  117. cm.list[x-1], cm.list[x] = cm.list[x], cm.list[x-1]
  118. x = x - 1
  119. } else {
  120. break
  121. }
  122. }
  123. }
  124. return cm.list[x].Set(key, offset, size)
  125. }
  126. func (cm *CompactMap) Delete(key NeedleId) uint32 {
  127. x := cm.binarySearchCompactSection(key)
  128. if x < 0 {
  129. return uint32(0)
  130. }
  131. return cm.list[x].Delete(key)
  132. }
  133. func (cm *CompactMap) Get(key NeedleId) (*NeedleValue, bool) {
  134. x := cm.binarySearchCompactSection(key)
  135. if x < 0 {
  136. return nil, false
  137. }
  138. return cm.list[x].Get(key)
  139. }
  140. func (cm *CompactMap) binarySearchCompactSection(key NeedleId) int {
  141. l, h := 0, len(cm.list)-1
  142. if h < 0 {
  143. return -5
  144. }
  145. if cm.list[h].start <= key {
  146. if cm.list[h].counter < batch || key <= cm.list[h].end {
  147. return h
  148. }
  149. return -4
  150. }
  151. for l <= h {
  152. m := (l + h) / 2
  153. if key < cm.list[m].start {
  154. h = m - 1
  155. } else { // cm.list[m].start <= key
  156. if cm.list[m+1].start <= key {
  157. l = m + 1
  158. } else {
  159. return m
  160. }
  161. }
  162. }
  163. return -3
  164. }
  165. // Visit visits all entries or stop if any error when visiting
  166. func (cm *CompactMap) Visit(visit func(NeedleValue) error) error {
  167. for _, cs := range cm.list {
  168. cs.RLock()
  169. for _, v := range cs.overflow {
  170. if err := visit(v); err != nil {
  171. cs.RUnlock()
  172. return err
  173. }
  174. }
  175. for _, v := range cs.values {
  176. if _, found := cs.overflow[v.Key]; !found {
  177. if err := visit(v); err != nil {
  178. cs.RUnlock()
  179. return err
  180. }
  181. }
  182. }
  183. cs.RUnlock()
  184. }
  185. return nil
  186. }