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.

189 lines
4.2 KiB

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