github.com/pingcap/badger@v1.5.1-0.20230103063557-828f39b09b6d/level_handler.go (about) 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 17 package badger 18 19 import ( 20 "fmt" 21 "sort" 22 "strings" 23 "sync" 24 25 "github.com/pingcap/badger/epoch" 26 "github.com/pingcap/badger/table" 27 "github.com/pingcap/badger/y" 28 "github.com/pingcap/errors" 29 "github.com/pingcap/log" 30 "go.uber.org/zap" 31 ) 32 33 type levelHandler struct { 34 // Guards tables, totalSize. 35 sync.RWMutex 36 37 // For level >= 1, tables are sorted by key ranges, which do not overlap. 38 // For level 0, tables are sorted by time. 39 // For level 0, newest table are at the back. Compact the oldest one first, which is at the front. 40 tables []table.Table 41 totalSize int64 42 43 // The following are initialized once and const. 44 level int 45 strLevel string 46 maxTotalSize int64 47 db *DB 48 metrics *y.LevelMetricsSet 49 } 50 51 func (s *levelHandler) getTotalSize() int64 { 52 s.RLock() 53 defer s.RUnlock() 54 return s.totalSize 55 } 56 57 // initTables replaces s.tables with given tables. This is done during loading. 58 func (s *levelHandler) initTables(tables []table.Table) { 59 s.Lock() 60 defer s.Unlock() 61 62 s.tables = tables 63 s.totalSize = 0 64 for _, t := range tables { 65 s.totalSize += t.Size() 66 } 67 68 if s.level == 0 { 69 // Key range will overlap. Just sort by fileID in ascending order 70 // because newer tables are at the end of level 0. 71 sort.Slice(s.tables, func(i, j int) bool { 72 return s.tables[i].ID() < s.tables[j].ID() 73 }) 74 } else { 75 // Sort tables by keys. 76 sortTables(s.tables) 77 } 78 } 79 80 // deleteTables remove tables idx0, ..., idx1-1. 81 func (s *levelHandler) deleteTables(toDel []table.Table, guard *epoch.Guard, isMove bool) { 82 s.Lock() // s.Unlock() below 83 84 toDelMap := make(map[uint64]struct{}) 85 for _, t := range toDel { 86 toDelMap[t.ID()] = struct{}{} 87 } 88 89 // Make a copy as iterators might be keeping a slice of tables. 90 var newTables []table.Table 91 for _, t := range s.tables { 92 _, found := toDelMap[t.ID()] 93 if !found { 94 newTables = append(newTables, t) 95 continue 96 } 97 s.totalSize -= t.Size() 98 } 99 s.tables = newTables 100 101 assertTablesOrder(s.level, newTables, nil) 102 s.Unlock() 103 104 if !isMove { 105 del := make([]epoch.Resource, len(toDel)) 106 for i := range toDel { 107 del[i] = toDel[i] 108 } 109 guard.Delete(del) 110 } 111 } 112 113 func assertTablesOrder(level int, tables []table.Table, cd *CompactDef) { 114 if level == 0 { 115 return 116 } 117 118 for i := 0; i < len(tables)-1; i++ { 119 if tables[i].Smallest().Compare(tables[i].Biggest()) > 0 || 120 tables[i].Smallest().Compare(tables[i+1].Smallest()) >= 0 || 121 tables[i].Biggest().Compare(tables[i+1].Biggest()) >= 0 { 122 123 var sb strings.Builder 124 if cd != nil { 125 fmt.Fprintf(&sb, "%s\n", cd) 126 } 127 fmt.Fprintf(&sb, "the order of level %d tables is invalid:\n", level) 128 for idx, tbl := range tables { 129 tag := " " 130 if idx == i { 131 tag = "->" 132 } 133 fmt.Fprintf(&sb, "%s %v %v\n", tag, tbl.Smallest(), tbl.Biggest()) 134 } 135 panic(sb.String()) 136 } 137 } 138 } 139 140 func sortTables(tables []table.Table) { 141 sort.Slice(tables, func(i, j int) bool { 142 return tables[i].Smallest().Compare(tables[j].Smallest()) < 0 143 }) 144 } 145 146 // replaceTables will replace tables[left:right] with newTables. Note this EXCLUDES tables[right]. 147 // You must call decr() to delete the old tables _after_ writing the update to the manifest. 148 func (s *levelHandler) replaceTables(newTables []table.Table, cd *CompactDef, guard *epoch.Guard) { 149 // Do not return even if len(newTables) is 0 because we need to delete bottom tables. 150 assertTablesOrder(s.level, newTables, cd) 151 152 s.Lock() // We s.Unlock() below. 153 154 // Increase totalSize first. 155 for _, tbl := range newTables { 156 s.totalSize += tbl.Size() 157 } 158 left, right := s.overlappingTables(levelHandlerRLocked{}, cd.nextRange) 159 toDelete := make([]epoch.Resource, 0, right-left) 160 // Update totalSize and reference counts. 161 for i := left; i < right; i++ { 162 tbl := s.tables[i] 163 if containsTable(cd.Bot, tbl) { 164 s.totalSize -= tbl.Size() 165 toDelete = append(toDelete, tbl) 166 } 167 } 168 tables := make([]table.Table, 0, left+len(newTables)+len(cd.SkippedTbls)+(len(s.tables)-right)) 169 tables = append(tables, s.tables[:left]...) 170 tables = append(tables, newTables...) 171 tables = append(tables, cd.SkippedTbls...) 172 tables = append(tables, s.tables[right:]...) 173 sortTables(tables) 174 assertTablesOrder(s.level, tables, cd) 175 s.tables = tables 176 s.Unlock() 177 guard.Delete(toDelete) 178 } 179 180 func containsTable(tables []table.Table, tbl table.Table) bool { 181 for _, t := range tables { 182 if tbl == t { 183 return true 184 } 185 } 186 return false 187 } 188 189 func newLevelHandler(db *DB, level int) *levelHandler { 190 label := fmt.Sprintf("L%d", level) 191 return &levelHandler{ 192 level: level, 193 strLevel: label, 194 db: db, 195 metrics: db.metrics.NewLevelMetricsSet(label), 196 } 197 } 198 199 // tryAddLevel0Table returns true if ok and no stalling. 200 func (s *levelHandler) tryAddLevel0Table(t table.Table) bool { 201 y.Assert(s.level == 0) 202 // Need lock as we may be deleting the first table during a level 0 compaction. 203 s.Lock() 204 defer s.Unlock() 205 // Return false only if number of tables is more than number of 206 // ZeroTableStall. For on disk L0, we should just add the tables to the level. 207 if len(s.tables) >= s.db.opt.NumLevelZeroTablesStall { 208 return false 209 } 210 211 s.tables = append(s.tables, t) 212 s.totalSize += t.Size() 213 214 return true 215 } 216 217 func (s *levelHandler) addTable(t table.Table) { 218 s.Lock() 219 defer s.Unlock() 220 221 s.totalSize += t.Size() 222 if s.level == 0 { 223 s.tables = append(s.tables, t) 224 return 225 } 226 227 i := sort.Search(len(s.tables), func(i int) bool { 228 return s.tables[i].Smallest().Compare(t.Biggest()) >= 0 229 }) 230 if i == len(s.tables) { 231 s.tables = append(s.tables, t) 232 } else { 233 s.tables = append(s.tables[:i+1], s.tables[i:]...) 234 s.tables[i] = t 235 } 236 } 237 238 func (s *levelHandler) numTables() int { 239 s.RLock() 240 defer s.RUnlock() 241 return len(s.tables) 242 } 243 244 func (s *levelHandler) close() error { 245 s.RLock() 246 defer s.RUnlock() 247 var err error 248 for _, t := range s.tables { 249 if closeErr := t.Close(); closeErr != nil && err == nil { 250 err = closeErr 251 } 252 } 253 return errors.Wrap(err, "levelHandler.close") 254 } 255 256 // getTablesForKey acquires a read-lock to access s.tables. It returns a list of tables. 257 func (s *levelHandler) getTablesForKey(key y.Key) []table.Table { 258 s.RLock() 259 defer s.RUnlock() 260 261 if s.level == 0 { 262 return s.getLevel0Tables() 263 } 264 tbl := s.getLevelNTable(key) 265 if tbl == nil { 266 return nil 267 } 268 return []table.Table{tbl} 269 } 270 271 // getTablesForKeys returns tables for pairs. 272 // level0 returns all tables. 273 // level1+ returns tables for every key. 274 func (s *levelHandler) getTablesForKeys(pairs []keyValuePair) []table.Table { 275 s.RLock() 276 defer s.RUnlock() 277 if s.level == 0 { 278 return s.getLevel0Tables() 279 } 280 out := make([]table.Table, len(pairs)) 281 for i, pair := range pairs { 282 out[i] = s.getLevelNTable(pair.key) 283 } 284 return out 285 } 286 287 func (s *levelHandler) getLevel0Tables() []table.Table { 288 // For level 0, we need to check every table. Remember to make a copy as s.tables may change 289 // once we exit this function, and we don't want to lock s.tables while seeking in tables. 290 // CAUTION: Reverse the tables. 291 out := make([]table.Table, 0, len(s.tables)) 292 for i := len(s.tables) - 1; i >= 0; i-- { 293 out = append(out, s.tables[i]) 294 } 295 return out 296 } 297 298 func (s *levelHandler) getLevelNTable(key y.Key) table.Table { 299 // For level >= 1, we can do a binary search as key range does not overlap. 300 idx := sort.Search(len(s.tables), func(i int) bool { 301 return s.tables[i].Biggest().Compare(key) >= 0 302 }) 303 if idx >= len(s.tables) { 304 // Given key is strictly > than every element we have. 305 return nil 306 } 307 tbl := s.tables[idx] 308 return tbl 309 } 310 311 // get returns value for a given key or the key after that. If not found, return nil. 312 func (s *levelHandler) get(key y.Key, keyHash uint64) y.ValueStruct { 313 tables := s.getTablesForKey(key) 314 return s.getInTables(key, keyHash, tables) 315 } 316 317 func (s *levelHandler) getInTables(key y.Key, keyHash uint64, tables []table.Table) y.ValueStruct { 318 for _, table := range tables { 319 result := s.getInTable(key, keyHash, table) 320 if result.Valid() { 321 return result 322 } 323 } 324 return y.ValueStruct{} 325 } 326 327 func (s *levelHandler) getInTable(key y.Key, keyHash uint64, table table.Table) y.ValueStruct { 328 s.metrics.NumLSMGets.Inc() 329 // TODO: error handling here 330 result, err := table.Get(key, keyHash) 331 if err != nil { 332 log.Error("get data in table failed", zap.Error(err)) 333 } 334 if !result.Valid() { 335 s.metrics.NumLSMBloomFalsePositive.Inc() 336 } 337 return result 338 } 339 340 func (s *levelHandler) multiGet(pairs []keyValuePair) { 341 tables := s.getTablesForKeys(pairs) 342 if s.level == 0 { 343 s.multiGetLevel0(pairs, tables) 344 } else { 345 s.multiGetLevelN(pairs, tables) 346 } 347 } 348 349 func (s *levelHandler) multiGetLevel0(pairs []keyValuePair, tables []table.Table) { 350 for _, table := range tables { 351 for i := range pairs { 352 pair := &pairs[i] 353 if pair.found { 354 continue 355 } 356 if pair.key.Compare(table.Smallest()) < 0 || pair.key.Compare(table.Biggest()) > 0 { 357 continue 358 } 359 for { 360 val := s.getInTable(pair.key, pair.hash, table) 361 if val.Valid() { 362 pair.val = val 363 pair.found = true 364 } 365 break 366 } 367 } 368 } 369 } 370 371 func (s *levelHandler) multiGetLevelN(pairs []keyValuePair, tables []table.Table) { 372 for i := range pairs { 373 pair := &pairs[i] 374 if pair.found { 375 continue 376 } 377 table := tables[i] 378 if table == nil { 379 continue 380 } 381 for { 382 val := s.getInTable(pair.key, pair.hash, table) 383 if val.Valid() { 384 pair.val = val 385 pair.found = true 386 } 387 break 388 } 389 } 390 } 391 392 // appendIterators appends iterators to an array of iterators, for merging. 393 // Note: This obtains references for the table handlers. Remember to close these iterators. 394 func (s *levelHandler) appendIterators(iters []y.Iterator, opts *IteratorOptions) []y.Iterator { 395 s.RLock() 396 defer s.RUnlock() 397 398 if s.level == 0 { 399 // Remember to add in reverse order! 400 // The newer table at the end of s.tables should be added first as it takes precedence. 401 overlapTables := make([]table.Table, 0, len(s.tables)) 402 for _, t := range s.tables { 403 if opts.OverlapTable(t) { 404 overlapTables = append(overlapTables, t) 405 } 406 } 407 return appendIteratorsReversed(iters, overlapTables, opts.Reverse) 408 } 409 overlapTables := opts.OverlapTables(s.tables) 410 if len(overlapTables) == 0 { 411 return iters 412 } 413 return append(iters, table.NewConcatIterator(overlapTables, opts.Reverse)) 414 } 415 416 type levelHandlerRLocked struct{} 417 418 // overlappingTables returns the tables that intersect with key range. Returns a half-interval. 419 // This function should already have acquired a read lock, and this is so important the caller must 420 // pass an empty parameter declaring such. 421 func (s *levelHandler) overlappingTables(_ levelHandlerRLocked, kr keyRange) (int, int) { 422 return getTablesInRange(s.tables, kr.left, kr.right) 423 } 424 425 func getTablesInRange(tbls []table.Table, start, end y.Key) (int, int) { 426 left := sort.Search(len(tbls), func(i int) bool { 427 return start.Compare(tbls[i].Biggest()) <= 0 428 }) 429 right := sort.Search(len(tbls), func(i int) bool { 430 return end.Compare(tbls[i].Smallest()) < 0 431 }) 432 return left, right 433 }