level_handler.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*
  2. * Copyright 2017 Dgraph Labs, Inc. and Contributors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package badger
  17. import (
  18. "fmt"
  19. "sort"
  20. "sync"
  21. "github.com/dgraph-io/badger/table"
  22. "github.com/dgraph-io/badger/y"
  23. "github.com/pkg/errors"
  24. )
  25. type levelHandler struct {
  26. // Guards tables, totalSize.
  27. sync.RWMutex
  28. // For level >= 1, tables are sorted by key ranges, which do not overlap.
  29. // For level 0, tables are sorted by time.
  30. // For level 0, newest table are at the back. Compact the oldest one first, which is at the front.
  31. tables []*table.Table
  32. totalSize int64
  33. // The following are initialized once and const.
  34. level int
  35. strLevel string
  36. maxTotalSize int64
  37. db *DB
  38. }
  39. func (s *levelHandler) getTotalSize() int64 {
  40. s.RLock()
  41. defer s.RUnlock()
  42. return s.totalSize
  43. }
  44. // initTables replaces s.tables with given tables. This is done during loading.
  45. func (s *levelHandler) initTables(tables []*table.Table) {
  46. s.Lock()
  47. defer s.Unlock()
  48. s.tables = tables
  49. s.totalSize = 0
  50. for _, t := range tables {
  51. s.totalSize += t.Size()
  52. }
  53. if s.level == 0 {
  54. // Key range will overlap. Just sort by fileID in ascending order
  55. // because newer tables are at the end of level 0.
  56. sort.Slice(s.tables, func(i, j int) bool {
  57. return s.tables[i].ID() < s.tables[j].ID()
  58. })
  59. } else {
  60. // Sort tables by keys.
  61. sort.Slice(s.tables, func(i, j int) bool {
  62. return y.CompareKeys(s.tables[i].Smallest(), s.tables[j].Smallest()) < 0
  63. })
  64. }
  65. }
  66. // deleteTables remove tables idx0, ..., idx1-1.
  67. func (s *levelHandler) deleteTables(toDel []*table.Table) error {
  68. s.Lock() // s.Unlock() below
  69. toDelMap := make(map[uint64]struct{})
  70. for _, t := range toDel {
  71. toDelMap[t.ID()] = struct{}{}
  72. }
  73. // Make a copy as iterators might be keeping a slice of tables.
  74. var newTables []*table.Table
  75. for _, t := range s.tables {
  76. _, found := toDelMap[t.ID()]
  77. if !found {
  78. newTables = append(newTables, t)
  79. continue
  80. }
  81. s.totalSize -= t.Size()
  82. }
  83. s.tables = newTables
  84. s.Unlock() // Unlock s _before_ we DecrRef our tables, which can be slow.
  85. return decrRefs(toDel)
  86. }
  87. // replaceTables will replace tables[left:right] with newTables. Note this EXCLUDES tables[right].
  88. // You must call decr() to delete the old tables _after_ writing the update to the manifest.
  89. func (s *levelHandler) replaceTables(newTables []*table.Table) error {
  90. // Need to re-search the range of tables in this level to be replaced as other goroutines might
  91. // be changing it as well. (They can't touch our tables, but if they add/remove other tables,
  92. // the indices get shifted around.)
  93. if len(newTables) == 0 {
  94. return nil
  95. }
  96. s.Lock() // We s.Unlock() below.
  97. // Increase totalSize first.
  98. for _, tbl := range newTables {
  99. s.totalSize += tbl.Size()
  100. tbl.IncrRef()
  101. }
  102. kr := keyRange{
  103. left: newTables[0].Smallest(),
  104. right: newTables[len(newTables)-1].Biggest(),
  105. }
  106. left, right := s.overlappingTables(levelHandlerRLocked{}, kr)
  107. toDecr := make([]*table.Table, right-left)
  108. // Update totalSize and reference counts.
  109. for i := left; i < right; i++ {
  110. tbl := s.tables[i]
  111. s.totalSize -= tbl.Size()
  112. toDecr[i-left] = tbl
  113. }
  114. // To be safe, just make a copy. TODO: Be more careful and avoid copying.
  115. numDeleted := right - left
  116. numAdded := len(newTables)
  117. tables := make([]*table.Table, len(s.tables)-numDeleted+numAdded)
  118. y.AssertTrue(left == copy(tables, s.tables[:left]))
  119. t := tables[left:]
  120. y.AssertTrue(numAdded == copy(t, newTables))
  121. t = t[numAdded:]
  122. y.AssertTrue(len(s.tables[right:]) == copy(t, s.tables[right:]))
  123. s.tables = tables
  124. s.Unlock() // s.Unlock before we DecrRef tables -- that can be slow.
  125. return decrRefs(toDecr)
  126. }
  127. func decrRefs(tables []*table.Table) error {
  128. for _, table := range tables {
  129. if err := table.DecrRef(); err != nil {
  130. return err
  131. }
  132. }
  133. return nil
  134. }
  135. func newLevelHandler(db *DB, level int) *levelHandler {
  136. return &levelHandler{
  137. level: level,
  138. strLevel: fmt.Sprintf("l%d", level),
  139. db: db,
  140. }
  141. }
  142. // tryAddLevel0Table returns true if ok and no stalling.
  143. func (s *levelHandler) tryAddLevel0Table(t *table.Table) bool {
  144. y.AssertTrue(s.level == 0)
  145. // Need lock as we may be deleting the first table during a level 0 compaction.
  146. s.Lock()
  147. defer s.Unlock()
  148. if len(s.tables) >= s.db.opt.NumLevelZeroTablesStall {
  149. return false
  150. }
  151. s.tables = append(s.tables, t)
  152. t.IncrRef()
  153. s.totalSize += t.Size()
  154. return true
  155. }
  156. func (s *levelHandler) numTables() int {
  157. s.RLock()
  158. defer s.RUnlock()
  159. return len(s.tables)
  160. }
  161. func (s *levelHandler) close() error {
  162. s.RLock()
  163. defer s.RUnlock()
  164. var err error
  165. for _, t := range s.tables {
  166. if closeErr := t.Close(); closeErr != nil && err == nil {
  167. err = closeErr
  168. }
  169. }
  170. return errors.Wrap(err, "levelHandler.close")
  171. }
  172. // getTableForKey acquires a read-lock to access s.tables. It returns a list of tableHandlers.
  173. func (s *levelHandler) getTableForKey(key []byte) ([]*table.Table, func() error) {
  174. s.RLock()
  175. defer s.RUnlock()
  176. if s.level == 0 {
  177. // For level 0, we need to check every table. Remember to make a copy as s.tables may change
  178. // once we exit this function, and we don't want to lock s.tables while seeking in tables.
  179. // CAUTION: Reverse the tables.
  180. out := make([]*table.Table, 0, len(s.tables))
  181. for i := len(s.tables) - 1; i >= 0; i-- {
  182. out = append(out, s.tables[i])
  183. s.tables[i].IncrRef()
  184. }
  185. return out, func() error {
  186. for _, t := range out {
  187. if err := t.DecrRef(); err != nil {
  188. return err
  189. }
  190. }
  191. return nil
  192. }
  193. }
  194. // For level >= 1, we can do a binary search as key range does not overlap.
  195. idx := sort.Search(len(s.tables), func(i int) bool {
  196. return y.CompareKeys(s.tables[i].Biggest(), key) >= 0
  197. })
  198. if idx >= len(s.tables) {
  199. // Given key is strictly > than every element we have.
  200. return nil, func() error { return nil }
  201. }
  202. tbl := s.tables[idx]
  203. tbl.IncrRef()
  204. return []*table.Table{tbl}, tbl.DecrRef
  205. }
  206. // get returns value for a given key or the key after that. If not found, return nil.
  207. func (s *levelHandler) get(key []byte) (y.ValueStruct, error) {
  208. tables, decr := s.getTableForKey(key)
  209. keyNoTs := y.ParseKey(key)
  210. var maxVs y.ValueStruct
  211. for _, th := range tables {
  212. if th.DoesNotHave(keyNoTs) {
  213. y.NumLSMBloomHits.Add(s.strLevel, 1)
  214. continue
  215. }
  216. it := th.NewIterator(false)
  217. defer it.Close()
  218. y.NumLSMGets.Add(s.strLevel, 1)
  219. it.Seek(key)
  220. if !it.Valid() {
  221. continue
  222. }
  223. if y.SameKey(key, it.Key()) {
  224. if version := y.ParseTs(it.Key()); maxVs.Version < version {
  225. maxVs = it.Value()
  226. maxVs.Version = version
  227. }
  228. }
  229. }
  230. return maxVs, decr()
  231. }
  232. // appendIterators appends iterators to an array of iterators, for merging.
  233. // Note: This obtains references for the table handlers. Remember to close these iterators.
  234. func (s *levelHandler) appendIterators(iters []y.Iterator, reversed bool) []y.Iterator {
  235. s.RLock()
  236. defer s.RUnlock()
  237. if s.level == 0 {
  238. // Remember to add in reverse order!
  239. // The newer table at the end of s.tables should be added first as it takes precedence.
  240. return appendIteratorsReversed(iters, s.tables, reversed)
  241. }
  242. return append(iters, table.NewConcatIterator(s.tables, reversed))
  243. }
  244. type levelHandlerRLocked struct{}
  245. // overlappingTables returns the tables that intersect with key range. Returns a half-interval.
  246. // This function should already have acquired a read lock, and this is so important the caller must
  247. // pass an empty parameter declaring such.
  248. func (s *levelHandler) overlappingTables(_ levelHandlerRLocked, kr keyRange) (int, int) {
  249. left := sort.Search(len(s.tables), func(i int) bool {
  250. return y.CompareKeys(kr.left, s.tables[i].Biggest()) <= 0
  251. })
  252. right := sort.Search(len(s.tables), func(i int) bool {
  253. return y.CompareKeys(kr.right, s.tables[i].Smallest()) < 0
  254. })
  255. return left, right
  256. }