compact_map.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. package needle_map
  2. import (
  3. "sort"
  4. "sync"
  5. . "github.com/chrislusf/seaweedfs/weed/storage/types"
  6. )
  7. const (
  8. batch = 100000
  9. )
  10. type SectionalNeedleId uint32
  11. const SectionalNeedleIdLimit = 1<<32 - 1
  12. type SectionalNeedleValue struct {
  13. Key SectionalNeedleId
  14. OffsetLower OffsetLower `comment:"Volume offset"` //since aligned to 8 bytes, range is 4G*8=32G
  15. Size Size `comment:"Size of the data portion"`
  16. }
  17. type SectionalNeedleValueExtra struct {
  18. OffsetHigher OffsetHigher
  19. }
  20. type CompactSection struct {
  21. sync.RWMutex
  22. values []SectionalNeedleValue
  23. valuesExtra []SectionalNeedleValueExtra
  24. overflow Overflow
  25. overflowExtra OverflowExtra
  26. start NeedleId
  27. end NeedleId
  28. counter int
  29. }
  30. type Overflow []SectionalNeedleValue
  31. type OverflowExtra []SectionalNeedleValueExtra
  32. func NewCompactSection(start NeedleId) *CompactSection {
  33. return &CompactSection{
  34. values: make([]SectionalNeedleValue, batch),
  35. valuesExtra: make([]SectionalNeedleValueExtra, batch),
  36. overflow: Overflow(make([]SectionalNeedleValue, 0)),
  37. overflowExtra: OverflowExtra(make([]SectionalNeedleValueExtra, 0)),
  38. start: start,
  39. }
  40. }
  41. //return old entry size
  42. func (cs *CompactSection) Set(key NeedleId, offset Offset, size Size) (oldOffset Offset, oldSize Size) {
  43. cs.Lock()
  44. if key > cs.end {
  45. cs.end = key
  46. }
  47. skey := SectionalNeedleId(key - cs.start)
  48. if i := cs.binarySearchValues(skey); i >= 0 {
  49. oldOffset.OffsetHigher, oldOffset.OffsetLower, oldSize = cs.valuesExtra[i].OffsetHigher, cs.values[i].OffsetLower, cs.values[i].Size
  50. //println("key", key, "old size", ret)
  51. cs.valuesExtra[i].OffsetHigher, cs.values[i].OffsetLower, cs.values[i].Size = offset.OffsetHigher, offset.OffsetLower, size
  52. } else {
  53. needOverflow := cs.counter >= batch
  54. needOverflow = needOverflow || cs.counter > 0 && cs.values[cs.counter-1].Key > skey
  55. if needOverflow {
  56. //println("start", cs.start, "counter", cs.counter, "key", key)
  57. if oldValueExtra, oldValue, found := cs.findOverflowEntry(skey); found {
  58. oldOffset.OffsetHigher, oldOffset.OffsetLower, oldSize = oldValueExtra.OffsetHigher, oldValue.OffsetLower, oldValue.Size
  59. }
  60. cs.setOverflowEntry(skey, offset, size)
  61. } else {
  62. p := &cs.values[cs.counter]
  63. p.Key, cs.valuesExtra[cs.counter].OffsetHigher, p.OffsetLower, p.Size = skey, offset.OffsetHigher, offset.OffsetLower, size
  64. //println("added index", cs.counter, "key", key, cs.values[cs.counter].Key)
  65. cs.counter++
  66. }
  67. }
  68. cs.Unlock()
  69. return
  70. }
  71. func (cs *CompactSection) setOverflowEntry(skey SectionalNeedleId, offset Offset, size Size) {
  72. needleValue := SectionalNeedleValue{Key: skey, OffsetLower: offset.OffsetLower, Size: size}
  73. needleValueExtra := SectionalNeedleValueExtra{OffsetHigher: offset.OffsetHigher}
  74. insertCandidate := sort.Search(len(cs.overflow), func(i int) bool {
  75. return cs.overflow[i].Key >= needleValue.Key
  76. })
  77. if insertCandidate != len(cs.overflow) && cs.overflow[insertCandidate].Key == needleValue.Key {
  78. cs.overflow[insertCandidate] = needleValue
  79. } else {
  80. cs.overflow = append(cs.overflow, needleValue)
  81. cs.overflowExtra = append(cs.overflowExtra, needleValueExtra)
  82. for i := len(cs.overflow) - 1; i > insertCandidate; i-- {
  83. cs.overflow[i] = cs.overflow[i-1]
  84. cs.overflowExtra[i] = cs.overflowExtra[i-1]
  85. }
  86. cs.overflow[insertCandidate] = needleValue
  87. }
  88. }
  89. func (cs *CompactSection) findOverflowEntry(key SectionalNeedleId) (nve SectionalNeedleValueExtra, nv SectionalNeedleValue, found bool) {
  90. foundCandidate := sort.Search(len(cs.overflow), func(i int) bool {
  91. return cs.overflow[i].Key >= key
  92. })
  93. if foundCandidate != len(cs.overflow) && cs.overflow[foundCandidate].Key == key {
  94. return cs.overflowExtra[foundCandidate], cs.overflow[foundCandidate], true
  95. }
  96. return nve, nv, false
  97. }
  98. func (cs *CompactSection) deleteOverflowEntry(key SectionalNeedleId) {
  99. length := len(cs.overflow)
  100. deleteCandidate := sort.Search(length, func(i int) bool {
  101. return cs.overflow[i].Key >= key
  102. })
  103. if deleteCandidate != length && cs.overflow[deleteCandidate].Key == key {
  104. if cs.overflow[deleteCandidate].Size.IsValid() {
  105. cs.overflow[deleteCandidate].Size = -cs.overflow[deleteCandidate].Size
  106. }
  107. }
  108. }
  109. //return old entry size
  110. func (cs *CompactSection) Delete(key NeedleId) Size {
  111. skey := SectionalNeedleId(key - cs.start)
  112. cs.Lock()
  113. ret := Size(0)
  114. if i := cs.binarySearchValues(skey); i >= 0 {
  115. if cs.values[i].Size > 0 && cs.values[i].Size.IsValid() {
  116. ret = cs.values[i].Size
  117. cs.values[i].Size = -cs.values[i].Size
  118. }
  119. }
  120. if _, v, found := cs.findOverflowEntry(skey); found {
  121. cs.deleteOverflowEntry(skey)
  122. ret = v.Size
  123. }
  124. cs.Unlock()
  125. return ret
  126. }
  127. func (cs *CompactSection) Get(key NeedleId) (*NeedleValue, bool) {
  128. cs.RLock()
  129. skey := SectionalNeedleId(key - cs.start)
  130. if ve, v, ok := cs.findOverflowEntry(skey); ok {
  131. cs.RUnlock()
  132. nv := toNeedleValue(ve, v, cs)
  133. return &nv, true
  134. }
  135. if i := cs.binarySearchValues(skey); i >= 0 {
  136. cs.RUnlock()
  137. nv := toNeedleValue(cs.valuesExtra[i], cs.values[i], cs)
  138. return &nv, true
  139. }
  140. cs.RUnlock()
  141. return nil, false
  142. }
  143. func (cs *CompactSection) binarySearchValues(key SectionalNeedleId) int {
  144. x := sort.Search(cs.counter, func(i int) bool {
  145. return cs.values[i].Key >= key
  146. })
  147. if x == cs.counter {
  148. return -1
  149. }
  150. if cs.values[x].Key > key {
  151. return -2
  152. }
  153. return x
  154. }
  155. //This map assumes mostly inserting increasing keys
  156. //This map assumes mostly inserting increasing keys
  157. type CompactMap struct {
  158. list []*CompactSection
  159. }
  160. func NewCompactMap() *CompactMap {
  161. return &CompactMap{}
  162. }
  163. func (cm *CompactMap) Set(key NeedleId, offset Offset, size Size) (oldOffset Offset, oldSize Size) {
  164. x := cm.binarySearchCompactSection(key)
  165. if x < 0 || (key-cm.list[x].start) > SectionalNeedleIdLimit {
  166. // println(x, "adding to existing", len(cm.list), "sections, starting", key)
  167. cs := NewCompactSection(key)
  168. cm.list = append(cm.list, cs)
  169. x = len(cm.list) - 1
  170. //keep compact section sorted by start
  171. for x >= 0 {
  172. if x > 0 && cm.list[x-1].start > key {
  173. cm.list[x] = cm.list[x-1]
  174. // println("shift", x, "start", cs.start, "to", x-1)
  175. x = x - 1
  176. } else {
  177. cm.list[x] = cs
  178. // println("cs", x, "start", cs.start)
  179. break
  180. }
  181. }
  182. }
  183. // println(key, "set to section[", x, "].start", cm.list[x].start)
  184. return cm.list[x].Set(key, offset, size)
  185. }
  186. func (cm *CompactMap) Delete(key NeedleId) Size {
  187. x := cm.binarySearchCompactSection(key)
  188. if x < 0 {
  189. return Size(0)
  190. }
  191. return cm.list[x].Delete(key)
  192. }
  193. func (cm *CompactMap) Get(key NeedleId) (*NeedleValue, bool) {
  194. x := cm.binarySearchCompactSection(key)
  195. if x < 0 {
  196. return nil, false
  197. }
  198. return cm.list[x].Get(key)
  199. }
  200. func (cm *CompactMap) binarySearchCompactSection(key NeedleId) int {
  201. l, h := 0, len(cm.list)-1
  202. if h < 0 {
  203. return -5
  204. }
  205. if cm.list[h].start <= key {
  206. if cm.list[h].counter < batch || key <= cm.list[h].end {
  207. return h
  208. }
  209. return -4
  210. }
  211. for l <= h {
  212. m := (l + h) / 2
  213. if key < cm.list[m].start {
  214. h = m - 1
  215. } else { // cm.list[m].start <= key
  216. if cm.list[m+1].start <= key {
  217. l = m + 1
  218. } else {
  219. return m
  220. }
  221. }
  222. }
  223. return -3
  224. }
  225. // Visit visits all entries or stop if any error when visiting
  226. func (cm *CompactMap) AscendingVisit(visit func(NeedleValue) error) error {
  227. for _, cs := range cm.list {
  228. cs.RLock()
  229. var i, j int
  230. for i, j = 0, 0; i < len(cs.overflow) && j < len(cs.values) && j < cs.counter; {
  231. if cs.overflow[i].Key < cs.values[j].Key {
  232. if err := visit(toNeedleValue(cs.overflowExtra[i], cs.overflow[i], cs)); err != nil {
  233. cs.RUnlock()
  234. return err
  235. }
  236. i++
  237. } else if cs.overflow[i].Key == cs.values[j].Key {
  238. j++
  239. } else {
  240. if err := visit(toNeedleValue(cs.valuesExtra[j], cs.values[j], cs)); err != nil {
  241. cs.RUnlock()
  242. return err
  243. }
  244. j++
  245. }
  246. }
  247. for ; i < len(cs.overflow); i++ {
  248. if err := visit(toNeedleValue(cs.overflowExtra[i], cs.overflow[i], cs)); err != nil {
  249. cs.RUnlock()
  250. return err
  251. }
  252. }
  253. for ; j < len(cs.values) && j < cs.counter; j++ {
  254. if err := visit(toNeedleValue(cs.valuesExtra[j], cs.values[j], cs)); err != nil {
  255. cs.RUnlock()
  256. return err
  257. }
  258. }
  259. cs.RUnlock()
  260. }
  261. return nil
  262. }
  263. func toNeedleValue(snve SectionalNeedleValueExtra, snv SectionalNeedleValue, cs *CompactSection) NeedleValue {
  264. offset := Offset{
  265. OffsetHigher: snve.OffsetHigher,
  266. OffsetLower: snv.OffsetLower,
  267. }
  268. return NeedleValue{Key: NeedleId(snv.Key) + cs.start, Offset: offset, Size: snv.Size}
  269. }
  270. func (nv NeedleValue) toSectionalNeedleValue(cs *CompactSection) (SectionalNeedleValue, SectionalNeedleValueExtra) {
  271. return SectionalNeedleValue{
  272. SectionalNeedleId(nv.Key - cs.start),
  273. nv.Offset.OffsetLower,
  274. nv.Size,
  275. }, SectionalNeedleValueExtra{
  276. nv.Offset.OffsetHigher,
  277. }
  278. }