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.

210 lines
4.6 KiB

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