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.

191 lines
4.2 KiB

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