github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitpage/bitpage.go (about) 1 // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bitpage 16 17 import ( 18 "arena" 19 "encoding/binary" 20 "errors" 21 "fmt" 22 "sort" 23 "sync" 24 25 "github.com/zuoyebang/bitalosdb/internal/base" 26 "github.com/zuoyebang/bitalosdb/internal/cache/lrucache" 27 "github.com/zuoyebang/bitalosdb/internal/consts" 28 "github.com/zuoyebang/bitalosdb/internal/options" 29 "github.com/zuoyebang/bitalosdb/internal/statemachine" 30 "github.com/zuoyebang/bitalosdb/internal/utils" 31 "github.com/zuoyebang/bitalosdb/internal/vfs" 32 ) 33 34 type FS vfs.FS 35 type File vfs.File 36 37 var ( 38 ErrPageNotFound = errors.New("page not exist") 39 ErrPageSplitted = errors.New("page splitted") 40 ErrPageNotSplitted = errors.New("page not splitted") 41 ErrPageFlushState = errors.New("page flush state err") 42 ErrTableFull = errors.New("allocation failed because table is full") 43 ErrTableSize = errors.New("tbl size is not large enough to hold the header") 44 ErrTableOpenType = errors.New("tbl open type not support") 45 ) 46 47 type Bitpage struct { 48 meta *bitpagemeta 49 opts *options.BitpageOptions 50 pages sync.Map 51 pageWriters sync.Map 52 splittedPages sync.Map 53 dirname string 54 index int 55 stats *Stats 56 dbState *statemachine.DbStateMachine 57 cache *lrucache.LruCache 58 stArena *arena.Arena 59 stArenaBuf []byte 60 } 61 62 type SplitPageInfo struct { 63 Pn PageNum 64 IsEmpty bool 65 Sentinel []byte 66 } 67 68 type PageDebugInfo struct { 69 Ct int64 70 Ut int64 71 SplitState uint8 72 } 73 74 type fileInfo struct { 75 ft FileType 76 fn FileNum 77 path string 78 } 79 80 func Open(dirname string, opts *options.BitpageOptions) (b *Bitpage, err error) { 81 b = &Bitpage{ 82 dirname: dirname, 83 opts: opts, 84 pages: sync.Map{}, 85 pageWriters: sync.Map{}, 86 splittedPages: sync.Map{}, 87 index: opts.Index, 88 stats: newStats(), 89 dbState: opts.DbState, 90 cache: nil, 91 } 92 93 if err = b.opts.FS.MkdirAll(dirname, 0755); err != nil { 94 return nil, err 95 } 96 97 if err = openManifest(b); err != nil { 98 return nil, err 99 } 100 101 if b.opts.UseBlockCompress { 102 cacheOpts := &options.CacheOptions{ 103 Size: b.opts.BitpageBlockCacheSize, 104 Shards: consts.BitpageBlockCacheShards, 105 HashSize: consts.BitpageBlockCacheHashSize, 106 Logger: b.opts.Logger, 107 } 108 b.cache = lrucache.NewLrucache(cacheOpts) 109 b.opts.Logger.Infof("bitpage new block cache ok index:%d size:%d", opts.Index, cacheOpts.Size) 110 } 111 112 defer b.freeStArenaBuf() 113 114 if err = b.openPages(); err != nil { 115 return nil, err 116 } 117 118 return b, nil 119 } 120 121 func (b *Bitpage) openPages() error { 122 files, err := b.opts.FS.List(b.dirname) 123 if err != nil { 124 return err 125 } 126 127 if len(files) == 0 { 128 return nil 129 } 130 131 sort.Strings(files) 132 133 pageFiles := make(map[PageNum][]fileInfo, 1<<10) 134 for i := range files { 135 ft, pn, fn, ok := parseFilename(files[i]) 136 if !ok || ft == fileTypeManifest { 137 continue 138 } 139 140 if _, exist := pageFiles[pn]; !exist { 141 b.SetPage(pn, newPage(b, pn)) 142 } 143 144 pageFiles[pn] = append(pageFiles[pn], fileInfo{ 145 ft: ft, 146 fn: fn, 147 path: b.opts.FS.PathJoin(b.dirname, files[i]), 148 }) 149 } 150 151 for pageNum, pm := range b.meta.mu.pagemetaMap { 152 p := b.GetPage(pageNum) 153 if p == nil { 154 p = newPage(b, pageNum) 155 b.SetPage(pageNum, p) 156 } else if err = p.openFiles(pm, pageFiles[pageNum]); err != nil { 157 return err 158 } 159 160 if b.PageSplitted(pageNum) { 161 if err = b.FreePage(pageNum, false); err != nil { 162 b.opts.Logger.Errorf("bitpage freePage fail index:%d pn:%s err:%s", b.index, pageNum, err.Error()) 163 } 164 } else { 165 b.setPageNoneSplit(pageNum) 166 if p.mu.stMutable == nil { 167 if err = p.makeMutableForWrite(false); err != nil { 168 return err 169 } 170 } 171 } 172 } 173 174 return nil 175 } 176 177 func (b *Bitpage) NewPage() (PageNum, error) { 178 p, err := b.newPageInternal() 179 if err != nil { 180 return PageNum(0), nil 181 } 182 return p.pn, nil 183 } 184 185 func (b *Bitpage) newPageInternal() (*page, error) { 186 pn := b.meta.getNextPageNum() 187 b.meta.newPagemetaItem(pn) 188 p := newPage(b, pn) 189 if err := p.makeMutableForWrite(false); err != nil { 190 b.meta.freePagemetaItem(pn) 191 return nil, err 192 } 193 194 b.SetPage(pn, p) 195 return p, nil 196 } 197 198 func (b *Bitpage) FreePage(pn PageNum, checked bool) error { 199 p := b.GetPage(pn) 200 if p == nil { 201 return ErrPageNotFound 202 } 203 204 if checked && !b.PageSplitted(pn) { 205 return ErrPageNotSplitted 206 } 207 208 if err := p.close(true); err != nil { 209 return err 210 } 211 212 b.pages.Delete(pn) 213 b.pageWriters.Delete(pn) 214 b.splittedPages.Delete(pn) 215 b.meta.freePagemetaItem(p.pn) 216 217 return nil 218 } 219 220 func (b *Bitpage) GetPageDebugInfo(pn PageNum) PageDebugInfo { 221 pinfo := PageDebugInfo{} 222 pm := b.meta.getPagemetaItem(pn) 223 if pm != nil { 224 pinfo.Ct = int64(pm.createTimestamp) 225 pinfo.Ut = int64(pm.updateTimestamp) 226 pinfo.SplitState = pm.splitState 227 } 228 229 return pinfo 230 } 231 232 func (b *Bitpage) GetPage(pn PageNum) *page { 233 p, ok := b.pages.Load(pn) 234 if !ok { 235 return nil 236 } 237 238 return p.(*page) 239 } 240 241 func (b *Bitpage) SetPage(pn PageNum, p *page) { 242 b.pages.Store(pn, p) 243 } 244 245 func (b *Bitpage) GetCacheMetrics() string { 246 if b.cache == nil { 247 return "" 248 } 249 return b.cache.MetricsInfo() 250 } 251 252 func (b *Bitpage) GetPageDelPercent(pn PageNum) float64 { 253 p := b.GetPage(pn) 254 if p == nil { 255 return 0 256 } 257 _, _, _, delPercent := p.inuseStState() 258 return delPercent 259 } 260 261 func (b *Bitpage) pageNoneSplit(pn PageNum) bool { 262 return b.meta.getSplitState(pn) == pageSplitStateNone 263 } 264 265 func (b *Bitpage) setPageNoneSplit(pn PageNum) { 266 b.meta.setSplitState(pn, pageSplitStateNone) 267 } 268 269 func (b *Bitpage) PageSplitted(pn PageNum) bool { 270 return b.meta.getSplitState(pn) == pageSplitStateFinish 271 } 272 273 func (b *Bitpage) PageSplitted2(pn PageNum) bool { 274 _, ok := b.splittedPages.Load(pn) 275 return ok 276 } 277 278 func (b *Bitpage) MarkFreePages(pns []PageNum) { 279 for i := range pns { 280 if b.GetPage(pns[i]) == nil { 281 continue 282 } 283 b.markFreePage(pns[i]) 284 } 285 } 286 287 func (b *Bitpage) markFreePage(pn PageNum) { 288 b.splittedPages.Store(pn, true) 289 b.meta.setSplitState(pn, pageSplitStateFinish) 290 } 291 292 func (b *Bitpage) CheckFreePages(except PageNum) bool { 293 isAllFree := true 294 b.pages.Range(func(pn, p interface{}) bool { 295 if pn == except { 296 return true 297 } 298 299 if b.PageSplitted(pn.(PageNum)) { 300 return true 301 } 302 303 isAllFree = false 304 return false 305 }) 306 307 return isAllFree 308 } 309 310 func (b *Bitpage) Get(pn PageNum, key []byte, khash uint32) ([]byte, bool, func(), base.InternalKeyKind) { 311 p := b.GetPage(pn) 312 if p == nil { 313 return nil, false, nil, internalKeyKindInvalid 314 } 315 return p.get(key, khash) 316 } 317 318 func (b *Bitpage) makeFilePath(ft FileType, pn PageNum, fn FileNum) string { 319 return makeFilepath(b.dirname, ft, pn, fn) 320 } 321 322 func (b *Bitpage) NewIter(pn PageNum, o *iterOptions) *PageIterator { 323 p := b.GetPage(pn) 324 if p == nil { 325 return nil 326 } 327 328 return p.newIter(o) 329 } 330 331 func (b *Bitpage) GetPageWriter(pn PageNum, sentinel []byte) *PageWriter { 332 pageWriter, ok := b.pageWriters.Load(pn) 333 if ok { 334 return pageWriter.(*PageWriter) 335 } 336 337 p := b.GetPage(pn) 338 if p == nil { 339 return nil 340 } 341 342 writer := &PageWriter{ 343 p: p, 344 Sentinel: utils.CloneBytes(sentinel), 345 } 346 b.pageWriters.Store(pn, writer) 347 348 return writer 349 } 350 351 func (b *Bitpage) Close() (err error) { 352 b.pages.Range(func(pn, p interface{}) bool { 353 err = p.(*page).close(false) 354 return true 355 }) 356 357 if b.meta != nil { 358 if err = b.meta.close(); err != nil { 359 b.opts.Logger.Errorf("bitpage close meta fail dir:%s err:%s", b.dirname, err.Error()) 360 } 361 } 362 363 if b.cache != nil { 364 b.cache.Close() 365 } 366 367 return nil 368 } 369 370 func (b *Bitpage) GetNeedFlushPageNums(isForce bool) []PageNum { 371 var pns []PageNum 372 b.pages.Range(func(pn, p interface{}) bool { 373 if pg, ok := p.(*page); ok { 374 if pg.maybeScheduleFlush(b.opts.BitpageFlushSize, isForce) { 375 pns = append(pns, pn.(PageNum)) 376 } 377 } 378 return true 379 }) 380 return pns 381 } 382 383 func (b *Bitpage) GetPageCount() int { 384 count := 0 385 b.pages.Range(func(pn, p interface{}) bool { 386 count++ 387 return true 388 }) 389 return count 390 } 391 392 func (b *Bitpage) PageFlush(pn PageNum, sentinel []byte, logTag string) error { 393 p := b.GetPage(pn) 394 if p == nil { 395 return ErrPageNotFound 396 } 397 398 defer p.setFlushState(pageFlushStateNone) 399 400 if !p.canFlush() { 401 return ErrPageFlushState 402 } 403 404 if b.PageSplitted(pn) { 405 return ErrPageSplitted 406 } 407 408 return p.flush(sentinel, logTag) 409 } 410 411 func (b *Bitpage) ManualPageFlush(pn PageNum) error { 412 p := b.GetPage(pn) 413 if p == nil { 414 return ErrPageNotFound 415 } 416 417 p.setFlushState(pageFlushStateSendTask) 418 return b.PageFlush(pn, nil, "") 419 } 420 421 func (b *Bitpage) PageSplitStart(pn PageNum, log string) (sps []*SplitPageInfo, err error) { 422 p := b.GetPage(pn) 423 if p == nil { 424 err = ErrPageNotFound 425 return 426 } 427 428 if b.meta.getSplitState(pn) >= pageSplitStateStart { 429 err = ErrPageSplitted 430 return 431 } 432 b.meta.setSplitState(pn, pageSplitStateStart) 433 434 var pages [consts.BitpageSplitNum]*page 435 var pns [consts.BitpageSplitNum]uint32 436 splitNum := consts.BitpageSplitNum 437 for i := 0; i < splitNum; i++ { 438 pages[i], err = b.newPageInternal() 439 if err != nil { 440 return 441 } 442 443 pns[i] = uint32(pages[i].pn) 444 } 445 446 logTag := fmt.Sprintf("%s split %s to %v", log, p.pn, pns) 447 if err = p.split(logTag, pages[:]); err != nil { 448 return 449 } 450 451 for i := 0; i < splitNum; i++ { 452 if pages[i] != nil { 453 sps = append(sps, &SplitPageInfo{ 454 Pn: pages[i].pn, 455 Sentinel: pages[i].maxKey, 456 }) 457 } 458 } 459 460 return 461 } 462 463 func (b *Bitpage) PageSplitEnd(pn PageNum, sps []*SplitPageInfo, retErr error) { 464 if retErr == nil { 465 for i := range sps { 466 b.meta.setNextArrayTableFileNum(sps[i].Pn) 467 } 468 b.markFreePage(pn) 469 } else { 470 if retErr == ErrPageSplitted || retErr == ErrPageNotFound { 471 return 472 } 473 474 b.setPageNoneSplit(pn) 475 for i := range sps { 476 if err := b.FreePage(sps[i].Pn, false); err != nil { 477 b.opts.Logger.Errorf("PageSplitEnd FreePage fail index:%d pn:%s err:%s", b.index, sps[i].Pn, err) 478 } 479 } 480 } 481 } 482 483 func (b *Bitpage) ResetStats() { 484 b.stats.Reset() 485 } 486 487 func (b *Bitpage) Stats() *Stats { 488 b.stats.Size = utils.GetDirSize(b.dirname) 489 490 return b.stats 491 } 492 493 func (b *Bitpage) StatsToString() string { 494 return b.stats.String() 495 } 496 497 func (b *Bitpage) deleteBithashKey(value []byte) { 498 if len(value) == 0 { 499 return 500 } 501 502 dv := base.DecodeInternalValue(value) 503 if dv.Kind() == base.InternalKeyKindSetBithash && base.CheckValueValidByKeySetBithash(dv.UserValue) { 504 fn := binary.LittleEndian.Uint32(dv.UserValue) 505 if err := b.opts.BithashDeleteCB(fn); err != nil { 506 b.opts.Logger.Errorf("delete bithash key fail err:%v", err) 507 } 508 } 509 } 510 511 func (b *Bitpage) getStArenaBuf(sz int) []byte { 512 alloc := utils.CalcBitsSize(sz) 513 514 if b.stArena == nil { 515 b.stArena = arena.NewArena() 516 b.stArenaBuf = arena.MakeSlice[byte](b.stArena, alloc, alloc) 517 } else if cap(b.stArenaBuf) < sz { 518 b.stArena.Free() 519 b.stArena = arena.NewArena() 520 b.stArenaBuf = arena.MakeSlice[byte](b.stArena, alloc, alloc) 521 } 522 523 return b.stArenaBuf 524 } 525 526 func (b *Bitpage) freeStArenaBuf() { 527 if b.stArena != nil { 528 b.stArena.Free() 529 b.stArena = nil 530 b.stArenaBuf = nil 531 } 532 }