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.

194 lines
4.3 KiB

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