compaction.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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. "bytes"
  19. "fmt"
  20. "log"
  21. "math"
  22. "sync"
  23. "github.com/dgraph-io/badger/v4/table"
  24. "github.com/dgraph-io/badger/v4/y"
  25. )
  26. type keyRange struct {
  27. left []byte
  28. right []byte
  29. inf bool
  30. size int64 // size is used for Key splits.
  31. }
  32. func (r keyRange) isEmpty() bool {
  33. return len(r.left) == 0 && len(r.right) == 0 && !r.inf
  34. }
  35. var infRange = keyRange{inf: true}
  36. func (r keyRange) String() string {
  37. return fmt.Sprintf("[left=%x, right=%x, inf=%v]", r.left, r.right, r.inf)
  38. }
  39. func (r keyRange) equals(dst keyRange) bool {
  40. return bytes.Equal(r.left, dst.left) &&
  41. bytes.Equal(r.right, dst.right) &&
  42. r.inf == dst.inf
  43. }
  44. func (r *keyRange) extend(kr keyRange) {
  45. // TODO(ibrahim): Is this needed?
  46. if kr.isEmpty() {
  47. return
  48. }
  49. if r.isEmpty() {
  50. *r = kr
  51. }
  52. if len(r.left) == 0 || y.CompareKeys(kr.left, r.left) < 0 {
  53. r.left = kr.left
  54. }
  55. if len(r.right) == 0 || y.CompareKeys(kr.right, r.right) > 0 {
  56. r.right = kr.right
  57. }
  58. if kr.inf {
  59. r.inf = true
  60. }
  61. }
  62. func (r keyRange) overlapsWith(dst keyRange) bool {
  63. // Empty keyRange always overlaps.
  64. if r.isEmpty() {
  65. return true
  66. }
  67. // TODO(ibrahim): Do you need this?
  68. // Empty dst doesn't overlap with anything.
  69. if dst.isEmpty() {
  70. return false
  71. }
  72. if r.inf || dst.inf {
  73. return true
  74. }
  75. // [dst.left, dst.right] ... [r.left, r.right]
  76. // If my left is greater than dst right, we have no overlap.
  77. if y.CompareKeys(r.left, dst.right) > 0 {
  78. return false
  79. }
  80. // [r.left, r.right] ... [dst.left, dst.right]
  81. // If my right is less than dst left, we have no overlap.
  82. if y.CompareKeys(r.right, dst.left) < 0 {
  83. return false
  84. }
  85. // We have overlap.
  86. return true
  87. }
  88. // getKeyRange returns the smallest and the biggest in the list of tables.
  89. // TODO(naman): Write a test for this. The smallest and the biggest should
  90. // be the smallest of the leftmost table and the biggest of the right most table.
  91. func getKeyRange(tables ...*table.Table) keyRange {
  92. if len(tables) == 0 {
  93. return keyRange{}
  94. }
  95. smallest := tables[0].Smallest()
  96. biggest := tables[0].Biggest()
  97. for i := 1; i < len(tables); i++ {
  98. if y.CompareKeys(tables[i].Smallest(), smallest) < 0 {
  99. smallest = tables[i].Smallest()
  100. }
  101. if y.CompareKeys(tables[i].Biggest(), biggest) > 0 {
  102. biggest = tables[i].Biggest()
  103. }
  104. }
  105. // We pick all the versions of the smallest and the biggest key. Note that version zero would
  106. // be the rightmost key, considering versions are default sorted in descending order.
  107. return keyRange{
  108. left: y.KeyWithTs(y.ParseKey(smallest), math.MaxUint64),
  109. right: y.KeyWithTs(y.ParseKey(biggest), 0),
  110. }
  111. }
  112. type levelCompactStatus struct {
  113. ranges []keyRange
  114. delSize int64
  115. }
  116. func (lcs *levelCompactStatus) debug() string {
  117. var b bytes.Buffer
  118. for _, r := range lcs.ranges {
  119. b.WriteString(r.String())
  120. }
  121. return b.String()
  122. }
  123. func (lcs *levelCompactStatus) overlapsWith(dst keyRange) bool {
  124. for _, r := range lcs.ranges {
  125. if r.overlapsWith(dst) {
  126. return true
  127. }
  128. }
  129. return false
  130. }
  131. func (lcs *levelCompactStatus) remove(dst keyRange) bool {
  132. final := lcs.ranges[:0]
  133. var found bool
  134. for _, r := range lcs.ranges {
  135. if !r.equals(dst) {
  136. final = append(final, r)
  137. } else {
  138. found = true
  139. }
  140. }
  141. lcs.ranges = final
  142. return found
  143. }
  144. type compactStatus struct {
  145. sync.RWMutex
  146. levels []*levelCompactStatus
  147. tables map[uint64]struct{}
  148. }
  149. func (cs *compactStatus) overlapsWith(level int, this keyRange) bool {
  150. cs.RLock()
  151. defer cs.RUnlock()
  152. thisLevel := cs.levels[level]
  153. return thisLevel.overlapsWith(this)
  154. }
  155. func (cs *compactStatus) delSize(l int) int64 {
  156. cs.RLock()
  157. defer cs.RUnlock()
  158. return cs.levels[l].delSize
  159. }
  160. type thisAndNextLevelRLocked struct{}
  161. // compareAndAdd will check whether we can run this compactDef. That it doesn't overlap with any
  162. // other running compaction. If it can be run, it would store this run in the compactStatus state.
  163. func (cs *compactStatus) compareAndAdd(_ thisAndNextLevelRLocked, cd compactDef) bool {
  164. cs.Lock()
  165. defer cs.Unlock()
  166. tl := cd.thisLevel.level
  167. y.AssertTruef(tl < len(cs.levels), "Got level %d. Max levels: %d", tl, len(cs.levels))
  168. thisLevel := cs.levels[cd.thisLevel.level]
  169. nextLevel := cs.levels[cd.nextLevel.level]
  170. if thisLevel.overlapsWith(cd.thisRange) {
  171. return false
  172. }
  173. if nextLevel.overlapsWith(cd.nextRange) {
  174. return false
  175. }
  176. // Check whether this level really needs compaction or not. Otherwise, we'll end up
  177. // running parallel compactions for the same level.
  178. // Update: We should not be checking size here. Compaction priority already did the size checks.
  179. // Here we should just be executing the wish of others.
  180. thisLevel.ranges = append(thisLevel.ranges, cd.thisRange)
  181. nextLevel.ranges = append(nextLevel.ranges, cd.nextRange)
  182. thisLevel.delSize += cd.thisSize
  183. for _, t := range append(cd.top, cd.bot...) {
  184. cs.tables[t.ID()] = struct{}{}
  185. }
  186. return true
  187. }
  188. func (cs *compactStatus) delete(cd compactDef) {
  189. cs.Lock()
  190. defer cs.Unlock()
  191. tl := cd.thisLevel.level
  192. y.AssertTruef(tl < len(cs.levels), "Got level %d. Max levels: %d", tl, len(cs.levels))
  193. thisLevel := cs.levels[cd.thisLevel.level]
  194. nextLevel := cs.levels[cd.nextLevel.level]
  195. thisLevel.delSize -= cd.thisSize
  196. found := thisLevel.remove(cd.thisRange)
  197. // The following check makes sense only if we're compacting more than one
  198. // table. In case of the max level, we might rewrite a single table to
  199. // remove stale data.
  200. if cd.thisLevel != cd.nextLevel && !cd.nextRange.isEmpty() {
  201. found = nextLevel.remove(cd.nextRange) && found
  202. }
  203. if !found {
  204. this := cd.thisRange
  205. next := cd.nextRange
  206. fmt.Printf("Looking for: %s in this level %d.\n", this, tl)
  207. fmt.Printf("This Level:\n%s\n", thisLevel.debug())
  208. fmt.Println()
  209. fmt.Printf("Looking for: %s in next level %d.\n", next, cd.nextLevel.level)
  210. fmt.Printf("Next Level:\n%s\n", nextLevel.debug())
  211. log.Fatal("keyRange not found")
  212. }
  213. for _, t := range append(cd.top, cd.bot...) {
  214. _, ok := cs.tables[t.ID()]
  215. y.AssertTrue(ok)
  216. delete(cs.tables, t.ID())
  217. }
  218. }