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.3 KiB

12 years ago
10 years ago
  1. package storage
  2. import "strconv"
  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. func (k Key) String() string {
  13. return strconv.FormatUint(uint64(k), 10)
  14. }
  15. type CompactSection struct {
  16. values []NeedleValue
  17. overflow map[Key]NeedleValue
  18. start Key
  19. end Key
  20. counter int
  21. }
  22. func NewCompactSection(start Key) *CompactSection {
  23. return &CompactSection{
  24. values: make([]NeedleValue, batch),
  25. overflow: make(map[Key]NeedleValue),
  26. start: start,
  27. }
  28. }
  29. //return old entry size
  30. func (cs *CompactSection) Set(key Key, offset uint32, size uint32) uint32 {
  31. ret := uint32(0)
  32. if key > cs.end {
  33. cs.end = key
  34. }
  35. if i := cs.binarySearchValues(key); i >= 0 {
  36. ret = cs.values[i].Size
  37. //println("key", key, "old size", ret)
  38. cs.values[i].Offset, cs.values[i].Size = offset, size
  39. } else {
  40. needOverflow := cs.counter >= batch
  41. needOverflow = needOverflow || cs.counter > 0 && cs.values[cs.counter-1].Key > key
  42. if needOverflow {
  43. //println("start", cs.start, "counter", cs.counter, "key", key)
  44. if oldValue, found := cs.overflow[key]; found {
  45. ret = oldValue.Size
  46. }
  47. cs.overflow[key] = NeedleValue{Key: key, Offset: offset, Size: size}
  48. } else {
  49. p := &cs.values[cs.counter]
  50. p.Key, p.Offset, p.Size = key, offset, size
  51. //println("added index", cs.counter, "key", key, cs.values[cs.counter].Key)
  52. cs.counter++
  53. }
  54. }
  55. return ret
  56. }
  57. //return old entry size
  58. func (cs *CompactSection) Delete(key Key) uint32 {
  59. ret := uint32(0)
  60. if i := cs.binarySearchValues(key); i >= 0 {
  61. if cs.values[i].Size > 0 {
  62. ret = cs.values[i].Size
  63. cs.values[i].Size = 0
  64. }
  65. }
  66. if v, found := cs.overflow[key]; found {
  67. delete(cs.overflow, key)
  68. ret = v.Size
  69. }
  70. return ret
  71. }
  72. func (cs *CompactSection) Get(key Key) (*NeedleValue, bool) {
  73. if v, ok := cs.overflow[key]; ok {
  74. return &v, true
  75. }
  76. if i := cs.binarySearchValues(key); i >= 0 {
  77. return &cs.values[i], true
  78. }
  79. return nil, false
  80. }
  81. func (cs *CompactSection) binarySearchValues(key Key) int {
  82. l, h := 0, cs.counter-1
  83. if h >= 0 && cs.values[h].Key < key {
  84. return -2
  85. }
  86. //println("looking for key", key)
  87. for l <= h {
  88. m := (l + h) / 2
  89. //println("mid", m, "key", cs.values[m].Key, cs.values[m].Offset, cs.values[m].Size)
  90. if cs.values[m].Key < key {
  91. l = m + 1
  92. } else if key < cs.values[m].Key {
  93. h = m - 1
  94. } else {
  95. //println("found", m)
  96. return m
  97. }
  98. }
  99. return -1
  100. }
  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 Key, offset uint32, size uint32) 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 Key) 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 Key) (*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 Key) 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. for _, v := range cs.overflow {
  169. if err := visit(v); err != nil {
  170. return err
  171. }
  172. }
  173. for _, v := range cs.values {
  174. if _, found := cs.overflow[v.Key]; !found {
  175. if err := visit(v); err != nil {
  176. return err
  177. }
  178. }
  179. }
  180. }
  181. return nil
  182. }