github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitpage/page.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 "bytes" 19 "sync" 20 "sync/atomic" 21 22 "github.com/zuoyebang/bitalosdb/internal/consts" 23 "github.com/zuoyebang/bitalosdb/internal/invariants" 24 "github.com/zuoyebang/bitalosdb/internal/utils" 25 ) 26 27 const ( 28 pageFlushStateNone uint32 = iota 29 pageFlushStateSendTask 30 pageFlushStateStart 31 pageFlushStateFinish 32 ) 33 34 const ( 35 pageSplitStateNone uint8 = iota 36 pageSplitStateSendTask 37 pageSplitStateStart 38 pageSplitStateFinish 39 ) 40 41 type page struct { 42 bp *Bitpage 43 pn PageNum 44 dirname string 45 maxKey []byte 46 flushState atomic.Uint32 47 48 mu struct { 49 sync.RWMutex 50 stMutable *superTable 51 stQueue flushableList 52 arrtable *flushableEntry 53 } 54 55 readState struct { 56 sync.RWMutex 57 val *readState 58 } 59 } 60 61 func newPage(bp *Bitpage, pn PageNum) *page { 62 return &page{ 63 bp: bp, 64 dirname: bp.dirname, 65 pn: pn, 66 } 67 } 68 69 func (p *page) openFiles(pm *pagemetaItem, files []fileInfo) error { 70 var deleteFiles []string 71 72 addDeleteFile := func(name string) { 73 if utils.IsFileNotExist(name) { 74 return 75 } 76 deleteFiles = append(deleteFiles, name) 77 } 78 79 for _, f := range files { 80 switch f.ft { 81 case fileTypeSuperTable: 82 if f.fn >= pm.nextStFileNum || f.fn < pm.minUnflushedStFileNum { 83 addDeleteFile(f.path) 84 } else if err := p.newSuperTable(f.path, f.fn, true); err != nil { 85 return err 86 } 87 case fileTypeArrayTable: 88 if f.fn == pm.curAtFileNum { 89 _, atEntry, err := p.newArrayTable(f.path, f.fn, true) 90 if err != nil { 91 return err 92 } 93 p.mu.arrtable = atEntry 94 } else { 95 addDeleteFile(f.path) 96 } 97 } 98 } 99 100 if len(deleteFiles) > 0 { 101 p.bp.opts.DeleteFilePacer.AddFiles(deleteFiles) 102 } 103 104 p.updateReadState() 105 106 return nil 107 } 108 109 func (p *page) makeMutableForWrite(flushIdx bool) error { 110 st := p.mu.stMutable 111 if st != nil { 112 if st.empty() { 113 return nil 114 } 115 116 if flushIdx { 117 if err := st.writeIdxToFile(); err != nil { 118 return err 119 } 120 } 121 } 122 123 fn := p.bp.meta.getNextStFileNum(p.pn) 124 path := p.bp.makeFilePath(fileTypeSuperTable, p.pn, fn) 125 if err := p.newSuperTable(path, fn, false); err != nil { 126 return err 127 } 128 129 p.updateReadState() 130 return nil 131 } 132 133 func (p *page) newSklTable(path string, fn FileNum, exist bool) error { 134 st, err := newSklTable(path, exist, p.bp) 135 if err != nil { 136 return err 137 } 138 139 invariants.SetFinalizer(st, checkSklTable) 140 141 entry := p.newFlushableEntry(st, fn) 142 entry.release = func() { 143 if err := st.close(); err != nil { 144 p.bp.opts.Logger.Errorf("bitpage close sklTable fail file:%s err:%s", path, err.Error()) 145 } 146 147 if entry.obsolete { 148 p.deleteObsoleteFile(path) 149 } 150 } 151 152 p.mu.stQueue = append(p.mu.stQueue, entry) 153 return nil 154 } 155 156 func (p *page) newSuperTable(path string, fn FileNum, exist bool) error { 157 st, err := newSuperTable(p, path, fn, exist) 158 if err != nil { 159 return err 160 } 161 162 invariants.SetFinalizer(st, checkSuperTable) 163 164 idxPath := st.getIdxFilePath() 165 entry := p.newFlushableEntry(st, fn) 166 entry.release = func() { 167 if entry.obsolete { 168 st.indexModified = false 169 } 170 171 if err := st.close(); err != nil { 172 p.bp.opts.Logger.Errorf("bitpage close superTable fail file:%s err:%s", path, err.Error()) 173 } 174 175 if entry.obsolete { 176 p.deleteObsoleteFile(path) 177 p.deleteObsoleteFile(idxPath) 178 } 179 } 180 181 p.mu.stMutable = st 182 p.mu.stQueue = append(p.mu.stQueue, entry) 183 184 return nil 185 } 186 187 func (p *page) newArrayTable(path string, fn FileNum, exist bool) (*arrayTable, *flushableEntry, error) { 188 var err error 189 var at *arrayTable 190 191 cacheOpts := atCacheOptions{ 192 cache: p.bp.cache, 193 id: (uint64(p.pn) << 32) | uint64(fn), 194 } 195 196 if exist { 197 at, err = openArrayTable(path, &cacheOpts) 198 } else { 199 opts := atOptions{ 200 useMapIndex: p.bp.opts.UseMapIndex, 201 usePrefixCompress: p.bp.opts.UsePrefixCompress, 202 useBlockCompress: p.bp.opts.UseBlockCompress, 203 blockSize: consts.BitpageBlockSize, 204 } 205 at, err = newArrayTable(path, &opts, &cacheOpts) 206 } 207 if err != nil { 208 return nil, nil, err 209 } 210 211 invariants.SetFinalizer(at, checkArrayTable) 212 213 entry := p.newFlushableEntry(at, fn) 214 entry.release = func() { 215 if err := at.close(); err != nil { 216 p.bp.opts.Logger.Errorf("bitpage close arrayTable fail file:%s err:%s", path, err.Error()) 217 } 218 219 if entry.obsolete { 220 p.deleteObsoleteFile(path) 221 } 222 } 223 224 return at, entry, nil 225 } 226 227 func (p *page) newFlushableEntry(f flushable, fn FileNum) *flushableEntry { 228 entry := &flushableEntry{ 229 flushable: f, 230 fileNum: fn, 231 obsolete: false, 232 } 233 entry.readerRefs.Store(1) 234 return entry 235 } 236 237 func (p *page) getFilesPath() []string { 238 var paths []string 239 for _, st := range p.mu.stQueue { 240 paths = append(paths, st.path()) 241 idxFile := st.idxFilePath() 242 if utils.IsFileExist(idxFile) { 243 paths = append(paths, idxFile) 244 } 245 } 246 if p.mu.arrtable != nil { 247 paths = append(paths, p.mu.arrtable.path()) 248 } 249 return paths 250 } 251 252 func (p *page) close(delete bool) error { 253 p.mu.Lock() 254 defer p.mu.Unlock() 255 256 p.readState.Lock() 257 if p.readState.val != nil { 258 p.readState.val.unref() 259 } 260 p.readState.Unlock() 261 262 for i := range p.mu.stQueue { 263 if delete { 264 p.mu.stQueue[i].setObsolete() 265 } 266 p.mu.stQueue[i].readerUnref() 267 } 268 269 if p.mu.arrtable != nil { 270 if delete { 271 p.mu.arrtable.setObsolete() 272 } 273 p.mu.arrtable.readerUnref() 274 } 275 276 return nil 277 } 278 279 func (p *page) inuseStState() (int, uint64, int, float64) { 280 p.mu.RLock() 281 defer p.mu.RUnlock() 282 283 var itemCount int 284 var size uint64 285 var delPercent float64 286 for i := range p.mu.stQueue { 287 itemCount += p.mu.stQueue[i].itemCount() 288 size += p.mu.stQueue[i].inuseBytes() 289 dp := p.mu.stQueue[i].delPercent() 290 if delPercent < dp { 291 delPercent = dp 292 } 293 } 294 295 return itemCount, size, len(p.mu.stQueue), delPercent 296 } 297 298 func (p *page) loadReadState() (*readState, func()) { 299 p.readState.RLock() 300 state := p.readState.val 301 state.stMutable.mmapRLock() 302 state.ref() 303 p.readState.RUnlock() 304 return state, func() { 305 state.stMutable.mmapRUnLock() 306 state.unref() 307 } 308 } 309 310 func (p *page) updateReadState() { 311 s := &readState{ 312 stMutable: p.mu.stMutable, 313 stQueue: p.mu.stQueue, 314 arrtable: p.mu.arrtable, 315 } 316 s.refcnt.Store(1) 317 318 for i := range s.stQueue { 319 s.stQueue[i].readerRef() 320 } 321 322 if s.arrtable != nil { 323 s.arrtable.readerRef() 324 } 325 326 p.readState.Lock() 327 old := p.readState.val 328 p.readState.val = s 329 p.readState.Unlock() 330 331 if old != nil { 332 old.unref() 333 } 334 } 335 336 func (p *page) get(key []byte, khash uint32) ([]byte, bool, func(), internalKeyKind) { 337 rs, rsCloser := p.loadReadState() 338 339 stIndex := len(rs.stQueue) - 1 340 for stIndex >= 0 { 341 st := rs.stQueue[stIndex] 342 val, exist, kind, _ := st.get(key, khash) 343 if exist { 344 switch kind { 345 case internalKeyKindSet, internalKeyKindPrefixDelete: 346 return val, true, rsCloser, kind 347 case internalKeyKindDelete: 348 rsCloser() 349 return nil, false, nil, kind 350 } 351 } 352 353 stIndex-- 354 } 355 356 if rs.arrtable != nil { 357 val, exist, _, atCloser := rs.arrtable.get(key, khash) 358 if exist { 359 closer := func() { 360 rsCloser() 361 if atCloser != nil { 362 atCloser() 363 } 364 } 365 return val, true, closer, internalKeyKindSet 366 } 367 } 368 369 rsCloser() 370 return nil, false, nil, internalKeyKindInvalid 371 } 372 373 func (p *page) newIter(o *iterOptions) *PageIterator { 374 rs, rsCloser := p.loadReadState() 375 376 buf := pageIterAllocPool.Get().(*pageIterAlloc) 377 dbi := &buf.dbi 378 *dbi = PageIterator{ 379 alloc: buf, 380 cmp: bytes.Compare, 381 equal: bytes.Equal, 382 readState: rs, 383 readStateCloser: rsCloser, 384 iter: &buf.merging, 385 key: &buf.key, 386 keyBuf: buf.keyBuf, 387 prefixOrFullSeekKey: buf.prefixOrFullSeekKey, 388 } 389 if o != nil { 390 dbi.opts = *o 391 } 392 dbi.opts.Logger = p.bp.opts.Logger 393 394 sts := rs.stQueue 395 mlevels := buf.mlevels[:0] 396 numMergingLevels := len(sts) 397 if rs.arrtable != nil { 398 numMergingLevels++ 399 } 400 if numMergingLevels > cap(mlevels) { 401 mlevels = make([]mergingIterLevel, 0, numMergingLevels) 402 } 403 404 for i := len(sts) - 1; i >= 0; i-- { 405 mlevels = append(mlevels, mergingIterLevel{ 406 iter: sts[i].newIter(&dbi.opts), 407 }) 408 } 409 410 if rs.arrtable != nil { 411 mlevels = append(mlevels, mergingIterLevel{ 412 iter: rs.arrtable.newIter(&dbi.opts), 413 }) 414 } 415 416 buf.merging.Init(&dbi.opts, dbi.cmp, mlevels...) 417 return dbi 418 } 419 420 func (p *page) set(key internalKey, value []byte) error { 421 p.mu.RLock() 422 st := p.mu.stMutable 423 p.mu.RUnlock() 424 425 st.kindStatis(key.Kind()) 426 return st.set(key, value) 427 } 428 429 func (p *page) deleteObsoleteFile(filename string) { 430 if utils.IsFileNotExist(filename) { 431 return 432 } 433 434 p.bp.opts.DeleteFilePacer.AddFile(filename) 435 } 436 437 func (p *page) canSendFlushTask() bool { 438 return p.getFlushState() == pageFlushStateNone 439 } 440 441 func (p *page) canFlush() bool { 442 return p.getFlushState() == pageFlushStateSendTask 443 } 444 445 func (p *page) getFlushState() uint32 { 446 return p.flushState.Load() 447 } 448 449 func (p *page) setFlushState(v uint32) { 450 p.flushState.Store(v) 451 } 452 453 func (p *page) maybeScheduleFlush(flushSize uint64, isForce bool) bool { 454 if !p.canSendFlushTask() { 455 return false 456 } 457 458 if isForce { 459 p.setFlushState(pageFlushStateSendTask) 460 return true 461 } 462 463 itemCount, stSize, stNum, delPercent := p.inuseStState() 464 if stSize > flushSize || 465 stNum > 1 || 466 consts.CheckFlushDelPercent(delPercent, stSize, flushSize) || 467 consts.CheckFlushItemCount(itemCount, stSize, flushSize) { 468 p.bp.opts.Logger.Infof("[BITPAGE %d] push flush task pn:%s flushSize:%d stSize:%d stNum:%d delPercent:%.2f itemCount:%d", 469 p.bp.index, p.pn, flushSize, stSize, stNum, delPercent, itemCount) 470 p.setFlushState(pageFlushStateSendTask) 471 return true 472 } 473 474 return false 475 } 476 477 func (p *page) memFlushFinish() error { 478 p.mu.RLock() 479 st := p.mu.stMutable 480 p.mu.RUnlock() 481 return st.mergeIndexes() 482 }