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.

182 lines
4.0 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. //glog.V(4).Infoln("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. //glog.V(4).Infoln("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. //glog.V(4).Infoln("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. //glog.V(4).Infoln("looking for key", key)
  84. for l <= h {
  85. m := (l + h) / 2
  86. //glog.V(4).Infoln("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. //glog.V(4).Infoln("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. //glog.V(4).Infoln(x, "creating", len(cm.list), "section1, starting", key)
  109. cm.list = append(cm.list, NewCompactSection(key))
  110. x = len(cm.list) - 1
  111. }
  112. return cm.list[x].Set(key, offset, size)
  113. }
  114. func (cm *CompactMap) Delete(key Key) uint32 {
  115. x := cm.binarySearchCompactSection(key)
  116. if x < 0 {
  117. return uint32(0)
  118. }
  119. return cm.list[x].Delete(key)
  120. }
  121. func (cm *CompactMap) Get(key Key) (*NeedleValue, bool) {
  122. x := cm.binarySearchCompactSection(key)
  123. if x < 0 {
  124. return nil, false
  125. }
  126. return cm.list[x].Get(key)
  127. }
  128. func (cm *CompactMap) binarySearchCompactSection(key Key) int {
  129. l, h := 0, len(cm.list)-1
  130. if h < 0 {
  131. return -5
  132. }
  133. if cm.list[h].start <= key {
  134. if cm.list[h].counter < batch || key <= cm.list[h].end {
  135. return h
  136. } else {
  137. return -4
  138. }
  139. }
  140. for l <= h {
  141. m := (l + h) / 2
  142. if key < cm.list[m].start {
  143. h = m - 1
  144. } else { // cm.list[m].start <= key
  145. if cm.list[m+1].start <= key {
  146. l = m + 1
  147. } else {
  148. return m
  149. }
  150. }
  151. }
  152. return -3
  153. }
  154. func (cm *CompactMap) Visit(visit func(NeedleValue) error) error {
  155. for _, cs := range cm.list {
  156. for _, v := range cs.overflow {
  157. if err := visit(v); err != nil {
  158. return err
  159. }
  160. }
  161. for _, v := range cs.values {
  162. if _, found := cs.overflow[v.Key]; !found {
  163. if err := visit(v); err != nil {
  164. return err
  165. }
  166. }
  167. }
  168. }
  169. return nil
  170. }