compact_map.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. package needle_map
  2. import (
  3. "sort"
  4. "sync"
  5. . "github.com/seaweedfs/seaweedfs/weed/storage/types"
  6. )
  7. const (
  8. batch = 10000
  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. lookBackIndex := cs.counter - 128
  57. if lookBackIndex < 0 {
  58. lookBackIndex = 0
  59. }
  60. if cs.counter < batch && cs.values[lookBackIndex].Key < skey {
  61. // still has capacity and only partially out of order
  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. for x := cs.counter - 1; x >= lookBackIndex; x-- {
  66. if cs.values[x].Key > cs.values[x+1].Key {
  67. cs.values[x], cs.values[x+1] = cs.values[x+1], cs.values[x]
  68. cs.valuesExtra[x], cs.valuesExtra[x+1] = cs.valuesExtra[x+1], cs.valuesExtra[x]
  69. } else {
  70. break
  71. }
  72. }
  73. cs.counter++
  74. } else {
  75. //println("start", cs.start, "counter", cs.counter, "key", key)
  76. if oldValueExtra, oldValue, found := cs.findOverflowEntry(skey); found {
  77. oldOffset.OffsetHigher, oldOffset.OffsetLower, oldSize = oldValueExtra.OffsetHigher, oldValue.OffsetLower, oldValue.Size
  78. }
  79. cs.setOverflowEntry(skey, offset, size)
  80. }
  81. } else {
  82. p := &cs.values[cs.counter]
  83. p.Key, cs.valuesExtra[cs.counter].OffsetHigher, p.OffsetLower, p.Size = skey, offset.OffsetHigher, offset.OffsetLower, size
  84. //println("added index", cs.counter, "key", key, cs.values[cs.counter].Key)
  85. cs.counter++
  86. }
  87. }
  88. cs.Unlock()
  89. return
  90. }
  91. func (cs *CompactSection) setOverflowEntry(skey SectionalNeedleId, offset Offset, size Size) {
  92. needleValue := SectionalNeedleValue{Key: skey, OffsetLower: offset.OffsetLower, Size: size}
  93. needleValueExtra := SectionalNeedleValueExtra{OffsetHigher: offset.OffsetHigher}
  94. insertCandidate := sort.Search(len(cs.overflow), func(i int) bool {
  95. return cs.overflow[i].Key >= needleValue.Key
  96. })
  97. if insertCandidate != len(cs.overflow) && cs.overflow[insertCandidate].Key == needleValue.Key {
  98. cs.overflow[insertCandidate] = needleValue
  99. } else {
  100. cs.overflow = append(cs.overflow, needleValue)
  101. cs.overflowExtra = append(cs.overflowExtra, needleValueExtra)
  102. for i := len(cs.overflow) - 1; i > insertCandidate; i-- {
  103. cs.overflow[i] = cs.overflow[i-1]
  104. cs.overflowExtra[i] = cs.overflowExtra[i-1]
  105. }
  106. cs.overflow[insertCandidate] = needleValue
  107. cs.overflowExtra[insertCandidate] = needleValueExtra
  108. }
  109. }
  110. func (cs *CompactSection) findOverflowEntry(key SectionalNeedleId) (nve SectionalNeedleValueExtra, nv SectionalNeedleValue, found bool) {
  111. foundCandidate := sort.Search(len(cs.overflow), func(i int) bool {
  112. return cs.overflow[i].Key >= key
  113. })
  114. if foundCandidate != len(cs.overflow) && cs.overflow[foundCandidate].Key == key {
  115. return cs.overflowExtra[foundCandidate], cs.overflow[foundCandidate], true
  116. }
  117. return nve, nv, false
  118. }
  119. func (cs *CompactSection) deleteOverflowEntry(key SectionalNeedleId) {
  120. length := len(cs.overflow)
  121. deleteCandidate := sort.Search(length, func(i int) bool {
  122. return cs.overflow[i].Key >= key
  123. })
  124. if deleteCandidate != length && cs.overflow[deleteCandidate].Key == key {
  125. if cs.overflow[deleteCandidate].Size.IsValid() {
  126. cs.overflow[deleteCandidate].Size = -cs.overflow[deleteCandidate].Size
  127. }
  128. }
  129. }
  130. // return old entry size
  131. func (cs *CompactSection) Delete(key NeedleId) Size {
  132. skey := SectionalNeedleId(key - cs.start)
  133. cs.Lock()
  134. ret := Size(0)
  135. if i := cs.binarySearchValues(skey); i >= 0 {
  136. if cs.values[i].Size > 0 && cs.values[i].Size.IsValid() {
  137. ret = cs.values[i].Size
  138. cs.values[i].Size = -cs.values[i].Size
  139. }
  140. }
  141. if _, v, found := cs.findOverflowEntry(skey); found {
  142. cs.deleteOverflowEntry(skey)
  143. ret = v.Size
  144. }
  145. cs.Unlock()
  146. return ret
  147. }
  148. func (cs *CompactSection) Get(key NeedleId) (*NeedleValue, bool) {
  149. cs.RLock()
  150. skey := SectionalNeedleId(key - cs.start)
  151. if ve, v, ok := cs.findOverflowEntry(skey); ok {
  152. cs.RUnlock()
  153. nv := toNeedleValue(ve, v, cs)
  154. return &nv, true
  155. }
  156. if i := cs.binarySearchValues(skey); i >= 0 {
  157. cs.RUnlock()
  158. nv := toNeedleValue(cs.valuesExtra[i], cs.values[i], cs)
  159. return &nv, true
  160. }
  161. cs.RUnlock()
  162. return nil, false
  163. }
  164. func (cs *CompactSection) binarySearchValues(key SectionalNeedleId) int {
  165. x := sort.Search(cs.counter, func(i int) bool {
  166. return cs.values[i].Key >= key
  167. })
  168. if x == cs.counter {
  169. return -1
  170. }
  171. if cs.values[x].Key > key {
  172. return -2
  173. }
  174. return x
  175. }
  176. // This map assumes mostly inserting increasing keys
  177. // This map assumes mostly inserting increasing keys
  178. type CompactMap struct {
  179. list []*CompactSection
  180. }
  181. func NewCompactMap() *CompactMap {
  182. return &CompactMap{}
  183. }
  184. func (cm *CompactMap) Set(key NeedleId, offset Offset, size Size) (oldOffset Offset, oldSize Size) {
  185. x := cm.binarySearchCompactSection(key)
  186. if x < 0 || (key-cm.list[x].start) > SectionalNeedleIdLimit {
  187. // println(x, "adding to existing", len(cm.list), "sections, starting", key)
  188. cs := NewCompactSection(key)
  189. cm.list = append(cm.list, cs)
  190. x = len(cm.list) - 1
  191. //keep compact section sorted by start
  192. for x >= 0 {
  193. if x > 0 && cm.list[x-1].start > key {
  194. cm.list[x] = cm.list[x-1]
  195. // println("shift", x, "start", cs.start, "to", x-1)
  196. x = x - 1
  197. } else {
  198. cm.list[x] = cs
  199. // println("cs", x, "start", cs.start)
  200. break
  201. }
  202. }
  203. }
  204. // println(key, "set to section[", x, "].start", cm.list[x].start)
  205. return cm.list[x].Set(key, offset, size)
  206. }
  207. func (cm *CompactMap) Delete(key NeedleId) Size {
  208. x := cm.binarySearchCompactSection(key)
  209. if x < 0 {
  210. return Size(0)
  211. }
  212. return cm.list[x].Delete(key)
  213. }
  214. func (cm *CompactMap) Get(key NeedleId) (*NeedleValue, bool) {
  215. x := cm.binarySearchCompactSection(key)
  216. if x < 0 {
  217. return nil, false
  218. }
  219. return cm.list[x].Get(key)
  220. }
  221. func (cm *CompactMap) binarySearchCompactSection(key NeedleId) int {
  222. l, h := 0, len(cm.list)-1
  223. if h < 0 {
  224. return -5
  225. }
  226. if cm.list[h].start <= key {
  227. if cm.list[h].counter < batch || key <= cm.list[h].end {
  228. return h
  229. }
  230. return -4
  231. }
  232. for l <= h {
  233. m := (l + h) / 2
  234. if key < cm.list[m].start {
  235. h = m - 1
  236. } else { // cm.list[m].start <= key
  237. if cm.list[m+1].start <= key {
  238. l = m + 1
  239. } else {
  240. return m
  241. }
  242. }
  243. }
  244. return -3
  245. }
  246. // Visit visits all entries or stop if any error when visiting
  247. func (cm *CompactMap) AscendingVisit(visit func(NeedleValue) error) error {
  248. for _, cs := range cm.list {
  249. cs.RLock()
  250. var i, j int
  251. for i, j = 0, 0; i < len(cs.overflow) && j < len(cs.values) && j < cs.counter; {
  252. if cs.overflow[i].Key < cs.values[j].Key {
  253. if err := visit(toNeedleValue(cs.overflowExtra[i], cs.overflow[i], cs)); err != nil {
  254. cs.RUnlock()
  255. return err
  256. }
  257. i++
  258. } else if cs.overflow[i].Key == cs.values[j].Key {
  259. j++
  260. } else {
  261. if err := visit(toNeedleValue(cs.valuesExtra[j], cs.values[j], cs)); err != nil {
  262. cs.RUnlock()
  263. return err
  264. }
  265. j++
  266. }
  267. }
  268. for ; i < len(cs.overflow); i++ {
  269. if err := visit(toNeedleValue(cs.overflowExtra[i], cs.overflow[i], cs)); err != nil {
  270. cs.RUnlock()
  271. return err
  272. }
  273. }
  274. for ; j < len(cs.values) && j < cs.counter; j++ {
  275. if err := visit(toNeedleValue(cs.valuesExtra[j], cs.values[j], cs)); err != nil {
  276. cs.RUnlock()
  277. return err
  278. }
  279. }
  280. cs.RUnlock()
  281. }
  282. return nil
  283. }
  284. func toNeedleValue(snve SectionalNeedleValueExtra, snv SectionalNeedleValue, cs *CompactSection) NeedleValue {
  285. offset := Offset{
  286. OffsetHigher: snve.OffsetHigher,
  287. OffsetLower: snv.OffsetLower,
  288. }
  289. return NeedleValue{Key: NeedleId(snv.Key) + cs.start, Offset: offset, Size: snv.Size}
  290. }
  291. func (nv NeedleValue) toSectionalNeedleValue(cs *CompactSection) (SectionalNeedleValue, SectionalNeedleValueExtra) {
  292. return SectionalNeedleValue{
  293. SectionalNeedleId(nv.Key - cs.start),
  294. nv.Offset.OffsetLower,
  295. nv.Size,
  296. }, SectionalNeedleValueExtra{
  297. nv.Offset.OffsetHigher,
  298. }
  299. }